From 9f3f9a7cdc94b25b90e8a41c539bbc723468aef9 Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Tue, 16 Jan 2024 17:20:42 +0100 Subject: [PATCH 01/35] first reimplementation of web3 holder provider --- api/holders.go | 2 +- api/tokens.go | 15 +-- service/holders_provider.go | 16 +-- service/poap/poap_provider.go | 93 +++++++------- service/web3/const.go | 39 +++++- service/web3/endpoint.go | 6 +- service/web3/erc20_provider.go | 218 +++++++++++++++++++++++++++++++++ service/web3/errors.go | 10 ++ service/web3/helpers.go | 42 +++++++ 9 files changed, 377 insertions(+), 64 deletions(-) create mode 100644 service/web3/erc20_provider.go create mode 100644 service/web3/errors.go create mode 100644 service/web3/helpers.go diff --git a/api/holders.go b/api/holders.go index cee792ca..bdd10516 100644 --- a/api/holders.go +++ b/api/holders.go @@ -116,7 +116,7 @@ func (capi *census3API) listHoldersAtLastBlock(address common.Address, if !exists { return nil, 0, ErrChainIDNotSupported.With("chain ID not supported") } - w3, err := w3URI.GetClient(web3.DefaultMaxRetries) + w3, err := w3URI.GetClient(web3.DefaultMaxWeb3ClientRetries) if err != nil { return nil, 0, ErrInitializingWeb3.WithErr(err) } diff --git a/api/tokens.go b/api/tokens.go index 79a16c0f..9cf4e017 100644 --- a/api/tokens.go +++ b/api/tokens.go @@ -227,27 +227,24 @@ func (capi *census3API) createToken(msg *api.APIdata, ctx *httprouter.HTTPContex tokenType := state.TokenTypeFromString(req.Type) if provider, exists := capi.extProviders[tokenType]; exists { // get token information from the external provider - address, err := provider.Address(internalCtx, []byte(req.ExternalID)) + address := provider.Address() + name, err := provider.Name([]byte(req.ExternalID)) if err != nil { return ErrCantGetToken.WithErr(err) } - name, err := provider.Name(internalCtx, []byte(req.ExternalID)) + symbol, err := provider.Symbol([]byte(req.ExternalID)) if err != nil { return ErrCantGetToken.WithErr(err) } - symbol, err := provider.Symbol(internalCtx, []byte(req.ExternalID)) + decimals, err := provider.Decimals([]byte(req.ExternalID)) if err != nil { return ErrCantGetToken.WithErr(err) } - decimals, err := provider.Decimals(internalCtx, []byte(req.ExternalID)) + totalSupply, err := provider.TotalSupply([]byte(req.ExternalID)) if err != nil { return ErrCantGetToken.WithErr(err) } - totalSupply, err := provider.TotalSupply(internalCtx, []byte(req.ExternalID)) - if err != nil { - return ErrCantGetToken.WithErr(err) - } - iconURI, err := provider.IconURI(internalCtx, []byte(req.ExternalID)) + iconURI, err := provider.IconURI([]byte(req.ExternalID)) if err != nil { return ErrCantGetToken.WithErr(err) } diff --git a/service/holders_provider.go b/service/holders_provider.go index a352332f..a923d4c2 100644 --- a/service/holders_provider.go +++ b/service/holders_provider.go @@ -27,15 +27,17 @@ type HolderProvider interface { // Close closes the provider and its internal structures. Close() error // Token realated methods - Address(ctx context.Context, id []byte) (common.Address, error) - Name(ctx context.Context, id []byte) (string, error) - Symbol(ctx context.Context, id []byte) (string, error) - Decimals(ctx context.Context, id []byte) (uint64, error) - TotalSupply(ctx context.Context, id []byte) (*big.Int, error) - BalanceOf(ctx context.Context, id []byte, addr common.Address) (*big.Int, error) + Address() common.Address + Type() uint64 + NetworkID() uint64 + Name(id []byte) (string, error) + Symbol(id []byte) (string, error) + Decimals(id []byte) (uint64, error) + TotalSupply(id []byte) (*big.Int, error) + BalanceOf(id []byte, addr common.Address) (*big.Int, error) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) LatestBlockNumber(ctx context.Context, id []byte) (uint64, error) CreationBlock(ctx context.Context, id []byte) (uint64, error) - IconURI(ctx context.Context, id []byte) (string, error) + IconURI(id []byte) (string, error) } diff --git a/service/poap/poap_provider.go b/service/poap/poap_provider.go index 4cd16b57..e3fd39d7 100644 --- a/service/poap/poap_provider.go +++ b/service/poap/poap_provider.go @@ -27,6 +27,7 @@ const ( POAP_URI = "/event/%s/poaps" // POAP_CONTRACT_ADDRESS is the address of the POAP contract. POAP_CONTRACT_ADDRESS = "0x22c1f6050e56d2876009903609a2cc3fef83b415" + POAP_CONTRACT_TYPE = uint64(10000) ) // EventAPIResponse is the struct that stores the response of the POAP API @@ -66,42 +67,6 @@ type POAPHolderProvider struct { snapshotsMtx *sync.RWMutex } -// Decimals method is not implemented in the POAP external provider. By default -// it returns 0 and nil error. -func (p *POAPHolderProvider) Decimals(_ context.Context, _ []byte) (uint64, error) { - return 0, nil -} - -// TotalSupply method is not implemented in the POAP external provider. By -// default it returns 0 and nil error. -func (p *POAPHolderProvider) TotalSupply(_ context.Context, _ []byte) (*big.Int, error) { - return big.NewInt(0), nil -} - -// BlockTimestamp method is not implemented in the POAP external provider. By -// default it returns an empty string and nil error. -func (p *POAPHolderProvider) BlockTimestamp(_ context.Context, _ uint64) (string, error) { - return "", nil -} - -// BlockRootHash method is not implemented in the POAP external provider. By -// default it returns an empty bytes slice and nil error. -func (p *POAPHolderProvider) BlockRootHash(_ context.Context, _ uint64) ([]byte, error) { - return []byte{}, nil -} - -// CreationBlock method is not implemented in the POAP external provider. By -// default it returns 0 and nil error. -func (p *POAPHolderProvider) CreationBlock(_ context.Context, _ []byte) (uint64, error) { - return 0, nil -} - -// Close method is not implemented in the POAP external provider. By default it -// returns nil error. -func (p *POAPHolderProvider) Close() error { - return nil -} - // Init initializes the POAP external provider with the database provided. // It returns an error if the POAP access token or api endpoint uri is not // defined. @@ -161,11 +126,25 @@ func (p *POAPHolderProvider) HoldersBalances(_ context.Context, id []byte, delta return partialBalances, nil } -func (p *POAPHolderProvider) Address(_ context.Context, _ []byte) (common.Address, error) { - return common.HexToAddress(POAP_CONTRACT_ADDRESS), nil +// Close method is not implemented in the POAP external provider. By default it +// returns nil error. +func (p *POAPHolderProvider) Close() error { + return nil +} + +func (p *POAPHolderProvider) Address() common.Address { + return common.HexToAddress(POAP_CONTRACT_ADDRESS) } -func (p *POAPHolderProvider) Name(_ context.Context, id []byte) (string, error) { +func (p *POAPHolderProvider) Type() uint64 { + return POAP_CONTRACT_TYPE +} + +func (p *POAPHolderProvider) NetworkID() uint64 { + return 1 +} + +func (p *POAPHolderProvider) Name(id []byte) (string, error) { info, err := p.getEventInfo(string(id)) if err != nil { return "", err @@ -173,7 +152,7 @@ func (p *POAPHolderProvider) Name(_ context.Context, id []byte) (string, error) return info.Name, nil } -func (p *POAPHolderProvider) Symbol(_ context.Context, id []byte) (string, error) { +func (p *POAPHolderProvider) Symbol(id []byte) (string, error) { info, err := p.getEventInfo(string(id)) if err != nil { return "", err @@ -181,7 +160,19 @@ func (p *POAPHolderProvider) Symbol(_ context.Context, id []byte) (string, error return fmt.Sprintf("%s:%s", POAP_SYMBOL_PREFIX, info.FancyID), nil } -func (p *POAPHolderProvider) BalanceOf(_ context.Context, id []byte, addr common.Address) (*big.Int, error) { +// Decimals method is not implemented in the POAP external provider. By default +// it returns 0 and nil error. +func (p *POAPHolderProvider) Decimals(_ []byte) (uint64, error) { + return 0, nil +} + +// TotalSupply method is not implemented in the POAP external provider. By +// default it returns 0 and nil error. +func (p *POAPHolderProvider) TotalSupply(_ []byte) (*big.Int, error) { + return big.NewInt(0), nil +} + +func (p *POAPHolderProvider) BalanceOf(id []byte, addr common.Address) (*big.Int, error) { // parse eventID from id eventID := string(id) // get the last stored snapshot @@ -196,6 +187,18 @@ func (p *POAPHolderProvider) BalanceOf(_ context.Context, id []byte, addr common return nil, fmt.Errorf("no snapshot found for eventID %s", eventID) } +// BlockTimestamp method is not implemented in the POAP external provider. By +// default it returns an empty string and nil error. +func (p *POAPHolderProvider) BlockTimestamp(_ context.Context, _ uint64) (string, error) { + return "", nil +} + +// BlockRootHash method is not implemented in the POAP external provider. By +// default it returns an empty bytes slice and nil error. +func (p *POAPHolderProvider) BlockRootHash(_ context.Context, _ uint64) ([]byte, error) { + return []byte{}, nil +} + func (p *POAPHolderProvider) LatestBlockNumber(_ context.Context, id []byte) (uint64, error) { // parse eventID from id eventID := string(id) @@ -208,7 +211,13 @@ func (p *POAPHolderProvider) LatestBlockNumber(_ context.Context, id []byte) (ui return 0, fmt.Errorf("no snapshot found for eventID %s", eventID) } -func (p *POAPHolderProvider) IconURI(_ context.Context, id []byte) (string, error) { +// CreationBlock method is not implemented in the POAP external provider. By +// default it returns 0 and nil error. +func (p *POAPHolderProvider) CreationBlock(_ context.Context, _ []byte) (uint64, error) { + return 0, nil +} + +func (p *POAPHolderProvider) IconURI(id []byte) (string, error) { info, err := p.getEventInfo(string(id)) if err != nil { return "", err diff --git a/service/web3/const.go b/service/web3/const.go index 330c15ec..bf274d06 100644 --- a/service/web3/const.go +++ b/service/web3/const.go @@ -3,12 +3,12 @@ package web3 import "time" const ( - DefaultMaxRetries = 3 + DefaultMaxWeb3ClientRetries = 3 ) - const ( shortNameSourceUri = "https://chainid.network/chains_mini.json" checkNetworkEndpointsTimeout = time.Second * 10 + timeLayout = "2006-01-02T15:04:05Z07:00" ) var DefaultNetworkEndpoint = &NetworkEndpoint{ @@ -17,3 +17,38 @@ var DefaultNetworkEndpoint = &NetworkEndpoint{ ShortName: "gor", URIs: []string{"https://eth-goerli.api.onfinality.io/public"}, } + +const ( + // OTHER CONSTANTS + MAX_SCAN_BLOCKS_PER_ITERATION = 1000000 + MAX_SCAN_LOGS_PER_ITERATION = 100000 + MAX_NEW_HOLDER_CANDIDATES_PER_ITERATION = 5000 + BLOCKS_TO_SCAN_AT_ONCE = uint64(20000) + NULL_ADDRESS = "0" +) + +const ( + // EVM LOG TOPICS + LOG_TOPIC_VENATION_DEPOSIT = "4566dfc29f6f11d13a418c26a02bef7c28bae749d4de47e4e6a7cddea6730d59" + LOG_TOPIC_VENATION_WITHDRAW = "f279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568" + LOG_TOPIC_ERC20_TRANSFER = "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + LOG_TOPIC_ERC1155_TRANSFER_SINGLE = "c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62" + LOG_TOPIC_ERC1155_TRANSFER_BATCH = "4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb" + LOG_TOPIC_WANT_DEPOSIT = "e1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c" + LOG_TOPIC_WANT_WITHDRAWAL = "7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65" + // Add more topics here +) + +type TokenType uint64 + +const ( + // CONTRACT TYPES + CONTRACT_TYPE_UNKNOWN TokenType = iota + CONTRACT_TYPE_ERC20 + CONTRACT_TYPE_ERC721 + CONTRACT_TYPE_ERC1155 + CONTRACT_TYPE_ERC777 + CONTRACT_TYPE_CUSTOM_NATION3_VENATION + CONTRACT_TYPE_CUSTOM_ARAGON_WANT + CONTRACT_TYPE_ERC721_BURNED +) diff --git a/service/web3/endpoint.go b/service/web3/endpoint.go index 74e6d196..04614cfb 100644 --- a/service/web3/endpoint.go +++ b/service/web3/endpoint.go @@ -36,10 +36,10 @@ func (n *NetworkEndpoint) GetClient(maxRetries int) (*ethclient.Client, error) { // GetChainIDByURI function returns the chainID of the web3 provider URI // provided. It dials the URI and gets the chainID from the web3 endpoint, // using the context provided and the GetClient method with the -// DefaultMaxRetries value. +// DefaultMaxWeb3ClientRetries value. func GetChainIDByURI(ctx context.Context, uri string) (uint64, error) { n := &NetworkEndpoint{URIs: []string{uri}} - cli, err := n.GetClient(DefaultMaxRetries) + cli, err := n.GetClient(DefaultMaxWeb3ClientRetries) if err != nil { return 0, err } @@ -110,7 +110,7 @@ func (nps NetworkEndpoints) String() string { func (nps NetworkEndpoints) CurrentBlockNumbers(ctx context.Context) (map[uint64]uint64, error) { blockNumbers := make(map[uint64]uint64) for _, endpoint := range nps { - cli, err := endpoint.GetClient(DefaultMaxRetries) + cli, err := endpoint.GetClient(DefaultMaxWeb3ClientRetries) if err != nil { return blockNumbers, err } diff --git a/service/web3/erc20_provider.go b/service/web3/erc20_provider.go new file mode 100644 index 00000000..2f36b3a9 --- /dev/null +++ b/service/web3/erc20_provider.go @@ -0,0 +1,218 @@ +package web3 + +import ( + "context" + "errors" + "fmt" + "math/big" + "strings" + "sync" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + erc20 "github.com/vocdoni/census3/contracts/erc/erc20" +) + +type ERC20HolderProvider struct { + HexAddress string + ChainID uint64 + Client *ethclient.Client + + contract *erc20.ERC20Contract + address common.Address + name string + symbol string + decimals uint64 + totalSupply *big.Int + creationBlock uint64 + + balances map[common.Address]*big.Int + balancesMtx sync.RWMutex + balancesBlock uint64 +} + +func (p *ERC20HolderProvider) Init() error { + if p.HexAddress == "" || p.ChainID == 0 || p.Client == nil { + return ErrInvalidProviderAttributes + } + p.address = common.HexToAddress(p.HexAddress) + var err error + p.contract, err = erc20.NewERC20Contract(p.address, p.Client) + if err != nil { + return errors.Join(ErrInitializingContract, fmt.Errorf("[ERC20] %s: %w", p.HexAddress, err)) + } + p.balancesBlock, err = p.CreationBlock(context.Background(), nil) + p.balances = make(map[common.Address]*big.Int) + p.balancesMtx = sync.RWMutex{} + return err +} + +func (p *ERC20HolderProvider) SetLastBalances(ctx context.Context, id []byte, balances map[common.Address]*big.Int, from uint64) error { + p.balancesMtx.Lock() + defer p.balancesMtx.Unlock() + + if from < p.balancesBlock { + return errors.New("from block is lower than the last block analyzed") + } + p.balancesBlock = from + p.balances = balances + return nil +} + +func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, _ uint64) (map[common.Address]*big.Int, error) { + // calculate the range of blocks to scan, by default take the last block + // scanned and scan to the latest block + fromBlock := p.balancesBlock + toBlock, err := p.LatestBlockNumber(ctx, nil) + if err != nil { + return nil, err + } + // if the range is too big, scan only a part of it using the constant + // BLOCKS_TO_SCAN_AT_ONCE + if toBlock > fromBlock+BLOCKS_TO_SCAN_AT_ONCE { + toBlock = fromBlock + BLOCKS_TO_SCAN_AT_ONCE + } + // iterate scanning the logs in the range of blocks until the last block + // is reached + for fromBlock < toBlock { + // compose the filter to get the logs of the ERC20 Transfer events + filter := ethereum.FilterQuery{ + Addresses: []common.Address{p.address}, + FromBlock: new(big.Int).SetUint64(fromBlock), + ToBlock: new(big.Int).SetUint64(toBlock), + Topics: [][]common.Hash{ + {common.HexToHash(LOG_TOPIC_ERC20_TRANSFER)}, + }, + } + // get the logs and check if there are any errors + logs, err := p.Client.FilterLogs(ctx, filter) + if err != nil { + // if the error is about the query returning more than the maximum + // allowed logs, split the range of blocks in half and try again + if strings.Contains(err.Error(), "query returned more than") { + toBlock = fromBlock + ((toBlock - fromBlock) / 2) + continue + } + return nil, errors.Join(ErrScanningTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.HexAddress, err)) + } + // iterate the logs and update the balances + for _, log := range logs { + logData, err := p.contract.ERC20ContractFilterer.ParseTransfer(log) + if err != nil { + return nil, errors.Join(ErrParsingTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.HexAddress, err)) + } + // update balances + p.balancesMtx.Lock() + if toBalance, ok := p.balances[logData.To]; ok { + p.balances[logData.To] = new(big.Int).Add(toBalance, logData.Value) + } else { + p.balances[logData.To] = logData.Value + } + if fromBalance, ok := p.balances[logData.From]; ok { + p.balances[logData.From] = new(big.Int).Sub(fromBalance, logData.Value) + } else { + p.balances[logData.From] = new(big.Int).Neg(logData.Value) + } + p.balancesMtx.Unlock() + } + } + return p.balances, nil +} + +func (p *ERC20HolderProvider) Close() error { + return nil +} + +func (p *ERC20HolderProvider) Address() common.Address { + return p.address +} + +func (p *ERC20HolderProvider) Type() TokenType { + return CONTRACT_TYPE_ERC20 +} + +func (p *ERC20HolderProvider) NetworkID() uint64 { + return p.ChainID +} + +func (p *ERC20HolderProvider) Name(_ []byte) (string, error) { + var err error + if p.name == "" { + p.name, err = p.contract.ERC20ContractCaller.Name(nil) + } + return p.name, err +} + +func (p *ERC20HolderProvider) Symbol(_ []byte) (string, error) { + var err error + if p.symbol == "" { + p.symbol, err = p.contract.ERC20ContractCaller.Symbol(nil) + } + return p.symbol, err +} + +func (p *ERC20HolderProvider) Decimals(_ []byte) (uint64, error) { + if p.decimals == 0 { + decimals, err := p.contract.ERC20ContractCaller.Decimals(nil) + if err != nil { + return 0, err + } + p.decimals = uint64(decimals) + } + return p.decimals, nil +} + +func (p *ERC20HolderProvider) TotalSupply(_ []byte) (*big.Int, error) { + var err error + if p.totalSupply == nil { + p.totalSupply, err = p.contract.ERC20ContractCaller.TotalSupply(nil) + } + return p.totalSupply, err +} + +func (p *ERC20HolderProvider) BalanceOf(_ []byte, addr common.Address) (*big.Int, error) { + return p.contract.ERC20ContractCaller.BalanceOf(nil, addr) +} + +func (p *ERC20HolderProvider) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) { + blockHeader, err := p.Client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) + if err != nil { + return "", err + } + return time.Unix(int64(blockHeader.Time), 0).Format(timeLayout), nil +} + +func (p *ERC20HolderProvider) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) { + blockHeader, err := p.Client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) + if err != nil { + return nil, err + } + return blockHeader.Root.Bytes(), nil +} + +func (p *ERC20HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) (uint64, error) { + lastBlockHeader, err := p.Client.HeaderByNumber(ctx, nil) + if err != nil { + return 0, err + } + return lastBlockHeader.Number.Uint64(), nil +} + +func (p *ERC20HolderProvider) CreationBlock(ctx context.Context, _ []byte) (uint64, error) { + var err error + if p.creationBlock != 0 { + var lastBlock uint64 + lastBlock, err = p.LatestBlockNumber(ctx, nil) + if err != nil { + return 0, err + } + p.creationBlock, err = creationBlockInRange(p.Client, ctx, p.address, 0, lastBlock) + } + return p.creationBlock, err +} + +func (p *ERC20HolderProvider) IconURI(_ []byte) (string, error) { + return "", nil +} diff --git a/service/web3/errors.go b/service/web3/errors.go new file mode 100644 index 00000000..8e27e0b1 --- /dev/null +++ b/service/web3/errors.go @@ -0,0 +1,10 @@ +package web3 + +import "fmt" + +var ( + ErrInvalidProviderAttributes = fmt.Errorf("invalid provider attributes") + ErrInitializingContract = fmt.Errorf("error initializing token contract") + ErrScanningTokenLogs = fmt.Errorf("error scanning token logs") + ErrParsingTokenLogs = fmt.Errorf("error parsing token logs") +) diff --git a/service/web3/helpers.go b/service/web3/helpers.go new file mode 100644 index 00000000..16c9da46 --- /dev/null +++ b/service/web3/helpers.go @@ -0,0 +1,42 @@ +package web3 + +import ( + "context" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" +) + +// creationBlockInRange function finds the block number of a contract between +// the bounds provided as start and end blocks. +func creationBlockInRange(client *ethclient.Client, ctx context.Context, addr common.Address, start, end uint64) (uint64, error) { + // if both block numbers are equal, return its value as birthblock + if start == end { + return start, nil + } + // find the middle block between start and end blocks and get the contract + // code at this block + midBlock := (start + end) / 2 + codeLen, err := sourceCodeLenAt(client, ctx, addr, midBlock) + if err != nil && !strings.Contains(err.Error(), fmt.Sprintf("No state available for block %d", midBlock)) { + return 0, err + } + // if any code is found, keep trying with the lower half of blocks until + // find the first. if not, keep trying with the upper half + if codeLen > 2 { + return creationBlockInRange(client, ctx, addr, start, midBlock) + } else { + return creationBlockInRange(client, ctx, addr, midBlock+1, end) + } +} + +// SourceCodeLenAt function returns the length of the current contract bytecode +// at the block number provided. +func sourceCodeLenAt(client *ethclient.Client, ctx context.Context, addr common.Address, atBlockNumber uint64) (int, error) { + blockNumber := new(big.Int).SetUint64(atBlockNumber) + sourceCode, err := client.CodeAt(ctx, addr, blockNumber) + return len(sourceCode), err +} From 77b09a1f72cb844822e0d4720aba2f630db0e4cb Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Tue, 16 Jan 2024 18:59:51 +0100 Subject: [PATCH 02/35] new erc20 holder provider following the holder provider interface, it works but it is not perfect --- api/api.go | 5 +- api/holders.go | 3 +- api/tokens.go | 113 +++++++++----------- cmd/census3/main.go | 5 +- service/holder_scanner_test.go | 15 ++- service/holders_provider.go | 2 +- service/holders_scanner.go | 189 ++++++++++++++++++++++----------- service/poap/poap_provider.go | 9 +- service/tokenholders.go | 140 ++++++++++++++++++++++++ service/tokenholders_test.go | 137 ++++++++++++++++++++++++ service/web3/const.go | 29 ++++- service/web3/erc20_provider.go | 30 ++++-- service/web3/helpers.go | 7 ++ 13 files changed, 525 insertions(+), 159 deletions(-) create mode 100644 service/tokenholders.go create mode 100644 service/tokenholders_test.go diff --git a/api/api.go b/api/api.go index 21cb8365..7718fdc0 100644 --- a/api/api.go +++ b/api/api.go @@ -9,7 +9,6 @@ import ( "github.com/vocdoni/census3/queue" "github.com/vocdoni/census3/service" "github.com/vocdoni/census3/service/web3" - "github.com/vocdoni/census3/state" "go.vocdoni.io/dvote/api/censusdb" storagelayer "go.vocdoni.io/dvote/data" "go.vocdoni.io/dvote/data/downloader" @@ -29,7 +28,7 @@ type Census3APIConf struct { DataDir string GroupKey string Web3Providers web3.NetworkEndpoints - ExtProviders map[state.TokenType]service.HolderProvider + ExtProviders map[uint64]service.HolderProvider AdminToken string } @@ -42,7 +41,7 @@ type census3API struct { w3p web3.NetworkEndpoints storage storagelayer.Storage downloader *downloader.Downloader - extProviders map[state.TokenType]service.HolderProvider + extProviders map[uint64]service.HolderProvider cache *lru.Cache[CacheKey, any] } diff --git a/api/holders.go b/api/holders.go index bdd10516..b969af28 100644 --- a/api/holders.go +++ b/api/holders.go @@ -13,7 +13,6 @@ import ( "github.com/ethereum/go-ethereum/common" queries "github.com/vocdoni/census3/db/sqlc" "github.com/vocdoni/census3/service/web3" - "github.com/vocdoni/census3/state" "go.vocdoni.io/dvote/httprouter" api "go.vocdoni.io/dvote/httprouter/apirest" "go.vocdoni.io/dvote/log" @@ -108,7 +107,7 @@ func (capi *census3API) listHoldersAtLastBlock(address common.Address, } // if the token is external, return an error // TODO: implement external token holders - if _, isExternal := capi.extProviders[state.TokenType(tokenData.TypeID)]; isExternal { + if _, isExternal := capi.extProviders[tokenData.TypeID]; isExternal { return nil, 0, ErrCantCreateCensus.With("not implemented for external providers") } // get correct web3 uri provider diff --git a/api/tokens.go b/api/tokens.go index 5a816c4b..b96d8f22 100644 --- a/api/tokens.go +++ b/api/tokens.go @@ -15,6 +15,7 @@ import ( queries "github.com/vocdoni/census3/db/sqlc" "github.com/vocdoni/census3/internal" "github.com/vocdoni/census3/lexer" + "github.com/vocdoni/census3/service/web3" "github.com/vocdoni/census3/state" "go.vocdoni.io/dvote/httprouter" api "go.vocdoni.io/dvote/httprouter/apirest" @@ -224,61 +225,47 @@ func (capi *census3API) createToken(msg *api.APIdata, ctx *httprouter.HTTPContex internalCtx, cancel := context.WithTimeout(ctx.Request.Context(), createTokenTimeout) defer cancel() - var info *state.TokenData - tokenType := state.TokenTypeFromString(req.Type) - if provider, exists := capi.extProviders[tokenType]; exists { - // get token information from the external provider - address := provider.Address() - name, err := provider.Name([]byte(req.ExternalID)) - if err != nil { - return ErrCantGetToken.WithErr(err) - } - symbol, err := provider.Symbol([]byte(req.ExternalID)) - if err != nil { - return ErrCantGetToken.WithErr(err) - } - decimals, err := provider.Decimals([]byte(req.ExternalID)) - if err != nil { - return ErrCantGetToken.WithErr(err) - } - totalSupply, err := provider.TotalSupply([]byte(req.ExternalID)) - if err != nil { - return ErrCantGetToken.WithErr(err) - } - iconURI, err := provider.IconURI([]byte(req.ExternalID)) + endpoint, ok := capi.w3p.EndpointByChainID(req.ChainID) + if !ok { + return ErrChainIDNotSupported.With("chain ID not supported") + } + tokenType := web3.TokenTypeFromString(req.Type) + provider, isExternal := capi.extProviders[tokenType] + if !isExternal { + client, err := endpoint.GetClient(web3.DefaultMaxWeb3ClientRetries) if err != nil { - return ErrCantGetToken.WithErr(err) + return ErrInitializingWeb3.WithErr(err) } - // build token information struct with the data from the external - // provider - info = &state.TokenData{ - Type: tokenType, - Address: address, - Name: name, - Symbol: symbol, - Decimals: decimals, - TotalSupply: totalSupply, - IconURI: iconURI, + provider = &web3.ERC20HolderProvider{ + HexAddress: req.ID, + ChainID: req.ChainID, + Client: client, } - } else { - addr := common.HexToAddress(req.ID) - // init web3 client to get the token information before register in the - // database - w3 := state.Web3{} - // get correct web3 uri provider - w3URI, exists := capi.w3p.EndpointByChainID(req.ChainID) - if !exists { - return ErrChainIDNotSupported.With("chain ID not supported") - } - // init web3 client to get the token information - err := w3.Init(internalCtx, w3URI, addr, tokenType) - if err != nil { + if err := provider.Init(); err != nil { return ErrInitializingWeb3.WithErr(err) } - // get token information from the web3 client - if info, err = w3.TokenData(); err != nil { - return ErrCantGetToken.WithErr(err) - } + } + // get token information from the external provider + address := provider.Address() + name, err := provider.Name([]byte(req.ExternalID)) + if err != nil { + return ErrCantGetToken.WithErr(err) + } + symbol, err := provider.Symbol([]byte(req.ExternalID)) + if err != nil { + return ErrCantGetToken.WithErr(err) + } + decimals, err := provider.Decimals([]byte(req.ExternalID)) + if err != nil { + return ErrCantGetToken.WithErr(err) + } + totalSupply, err := provider.TotalSupply([]byte(req.ExternalID)) + if err != nil { + return ErrCantGetToken.WithErr(err) + } + iconURI, err := provider.IconURI([]byte(req.ExternalID)) + if err != nil { + return ErrCantGetToken.WithErr(err) } // init db transaction tx, err := capi.db.RW.BeginTx(internalCtx, nil) @@ -291,29 +278,29 @@ func (capi *census3API) createToken(msg *api.APIdata, ctx *httprouter.HTTPContex } }() // get the chain address for the token based on the chainID and tokenID - chainAddress, ok := capi.w3p.ChainAddress(req.ChainID, info.Address.String()) + chainAddress, ok := capi.w3p.ChainAddress(req.ChainID, address.String()) if !ok { return ErrChainIDNotSupported.Withf("chainID: %d, tokenID: %s", req.ChainID, req.ID) } - totalSupply := big.NewInt(0).String() - if info.TotalSupply != nil { - totalSupply = info.TotalSupply.String() + sTotalSupply := big.NewInt(0).String() + if totalSupply != nil { + sTotalSupply = totalSupply.String() } qtx := capi.db.QueriesRW.WithTx(tx) _, err = qtx.CreateToken(internalCtx, queries.CreateTokenParams{ - ID: info.Address.Bytes(), - Name: info.Name, - Symbol: info.Symbol, - Decimals: info.Decimals, - TotalSupply: annotations.BigInt(totalSupply), + ID: address.Bytes(), + Name: name, + Symbol: symbol, + Decimals: decimals, + TotalSupply: annotations.BigInt(sTotalSupply), CreationBlock: 0, - TypeID: uint64(tokenType), + TypeID: tokenType, Synced: false, Tags: req.Tags, ChainID: req.ChainID, ChainAddress: chainAddress, ExternalID: req.ExternalID, - IconUri: info.IconURI, + IconUri: iconURI, }) if err != nil { if strings.Contains(err.Error(), "UNIQUE constraint failed") { @@ -322,12 +309,12 @@ func (capi *census3API) createToken(msg *api.APIdata, ctx *httprouter.HTTPContex return ErrCantCreateToken.WithErr(err) } strategyID, err := capi.createDefaultTokenStrategy(internalCtx, qtx, - info.Address, req.ChainID, chainAddress, info.Symbol, req.ExternalID) + address, req.ChainID, chainAddress, symbol, req.ExternalID) if err != nil { return ErrCantCreateToken.WithErr(err) } if _, err := qtx.UpdateTokenDefaultStrategy(internalCtx, queries.UpdateTokenDefaultStrategyParams{ - ID: info.Address.Bytes(), + ID: address.Bytes(), DefaultStrategy: uint64(strategyID), ChainID: req.ChainID, ExternalID: req.ExternalID, diff --git a/cmd/census3/main.go b/cmd/census3/main.go index e53f9243..9d300a1c 100644 --- a/cmd/census3/main.go +++ b/cmd/census3/main.go @@ -19,7 +19,6 @@ import ( "github.com/vocdoni/census3/service" "github.com/vocdoni/census3/service/poap" "github.com/vocdoni/census3/service/web3" - "github.com/vocdoni/census3/state" "go.vocdoni.io/dvote/log" ) @@ -126,8 +125,8 @@ func main() { log.Fatal(err) } // start the holder scanner with the database and the external providers - externalProviders := map[state.TokenType]service.HolderProvider{ - state.CONTRACT_TYPE_POAP: poapProvider, + externalProviders := map[uint64]service.HolderProvider{ + web3.CONTRACT_TYPE_POAP: poapProvider, } hc, err := service.NewHoldersScanner(database, w3p, externalProviders, config.scannerCoolDown) if err != nil { diff --git a/service/holder_scanner_test.go b/service/holder_scanner_test.go index 8fd700e8..d0d805b7 100644 --- a/service/holder_scanner_test.go +++ b/service/holder_scanner_test.go @@ -12,7 +12,6 @@ import ( qt "github.com/frankban/quicktest" queries "github.com/vocdoni/census3/db/sqlc" "github.com/vocdoni/census3/service/web3" - "github.com/vocdoni/census3/state" ) var ( @@ -82,7 +81,7 @@ func Test_getTokensToScan(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() _, err = testdb.db.QueriesRW.CreateToken(ctx, testTokenParams("0x1", "test0", - "test0", 0, MonkeysDecimals, uint64(state.CONTRACT_TYPE_ERC20), + "test0", 0, MonkeysDecimals, uint64(web3.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) c.Assert(err, qt.IsNil) @@ -92,7 +91,7 @@ func Test_getTokensToScan(t *testing.T) { c.Assert(hs.tokens[0].Address().String(), qt.Equals, common.HexToAddress("0x1").String()) _, err = testdb.db.QueriesRW.CreateToken(ctx, testTokenParams("0x2", "test2", - "test3", 10, MonkeysDecimals, uint64(state.CONTRACT_TYPE_ERC20), + "test3", 10, MonkeysDecimals, uint64(web3.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) c.Assert(err, qt.IsNil) @@ -111,12 +110,12 @@ func Test_saveHolders(t *testing.T) { hs, err := NewHoldersScanner(testdb.db, web3Endpoints, nil, 20) c.Assert(err, qt.IsNil) - th := new(state.TokenHolders).Init(MonkeysAddress, state.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") // no registered token c.Assert(hs.saveHolders(th), qt.ErrorIs, ErrTokenNotExists) _, err = testdb.db.QueriesRW.CreateToken(context.Background(), testTokenParams( MonkeysAddress.String(), MonkeysName, MonkeysSymbol, MonkeysCreationBlock, - MonkeysDecimals, uint64(state.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) + MonkeysDecimals, uint64(web3.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) c.Assert(err, qt.IsNil) // check no new holders c.Assert(hs.saveHolders(th), qt.IsNil) @@ -177,7 +176,7 @@ func Test_scanHolders(t *testing.T) { _, err = testdb.db.QueriesRW.CreateToken(context.Background(), testTokenParams( MonkeysAddress.String(), MonkeysName, MonkeysSymbol, MonkeysCreationBlock, - MonkeysDecimals, uint64(state.CONTRACT_TYPE_ERC20), 10, false, 5, "")) + MonkeysDecimals, uint64(web3.CONTRACT_TYPE_ERC20), 10, false, 5, "")) c.Assert(err, qt.IsNil) // token exists and the scanner gets the holders ctx2, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -203,13 +202,13 @@ func Test_calcTokenCreationBlock(t *testing.T) { defer testdb.Close(t) hs, err := NewHoldersScanner(testdb.db, web3Endpoints, nil, 20) - hs.tokens = append(hs.tokens, new(state.TokenHolders).Init(MonkeysAddress, state.CONTRACT_TYPE_ERC20, 0, 5, "")) + hs.tokens = append(hs.tokens, new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, 0, 5, "")) c.Assert(err, qt.IsNil) c.Assert(hs.calcTokenCreationBlock(context.Background(), 5), qt.IsNotNil) _, err = testdb.db.QueriesRW.CreateToken(context.Background(), testTokenParams( MonkeysAddress.String(), MonkeysName, MonkeysSymbol, MonkeysCreationBlock, - MonkeysDecimals, uint64(state.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) + MonkeysDecimals, uint64(web3.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) c.Assert(err, qt.IsNil) c.Assert(hs.calcTokenCreationBlock(context.Background(), 0), qt.IsNil) diff --git a/service/holders_provider.go b/service/holders_provider.go index a923d4c2..94632fe3 100644 --- a/service/holders_provider.go +++ b/service/holders_provider.go @@ -23,7 +23,7 @@ type HolderProvider interface { SetLastBalances(ctx context.Context, id []byte, balances map[common.Address]*big.Int, from uint64) error // HoldersBalances returns the balances of the token holders for the given // id and delta point in time, from the stored last snapshot. - HoldersBalances(ctx context.Context, id []byte, to uint64) (map[common.Address]*big.Int, error) + HoldersBalances(ctx context.Context, id []byte, to uint64) (map[common.Address]*big.Int, uint64, error) // Close closes the provider and its internal structures. Close() error // Token realated methods diff --git a/service/holders_scanner.go b/service/holders_scanner.go index 9f3fa75c..82737c75 100644 --- a/service/holders_scanner.go +++ b/service/holders_scanner.go @@ -18,7 +18,6 @@ import ( "github.com/vocdoni/census3/db" queries "github.com/vocdoni/census3/db/sqlc" "github.com/vocdoni/census3/service/web3" - "github.com/vocdoni/census3/state" "go.vocdoni.io/dvote/log" ) @@ -33,11 +32,11 @@ var ( // keeps the database updated scanning the network using the web3 endpoint. type HoldersScanner struct { w3p web3.NetworkEndpoints - tokens []*state.TokenHolders + tokens []*TokenHolders mutex sync.RWMutex db *db.DB lastBlock uint64 - extProviders map[state.TokenType]HolderProvider + extProviders map[uint64]HolderProvider coolDown time.Duration } @@ -45,7 +44,7 @@ type HoldersScanner struct { // and the web3 endpoint URI provided. It sets up a sqlite3 database instance // and gets the number of last block scanned from it. func NewHoldersScanner(db *db.DB, w3p web3.NetworkEndpoints, - ext map[state.TokenType]HolderProvider, coolDown time.Duration, + ext map[uint64]HolderProvider, coolDown time.Duration, ) (*HoldersScanner, error) { if db == nil { return nil, ErrNoDB @@ -53,7 +52,7 @@ func NewHoldersScanner(db *db.DB, w3p web3.NetworkEndpoints, // create an empty scanner s := HoldersScanner{ w3p: w3p, - tokens: []*state.TokenHolders{}, + tokens: []*TokenHolders{}, db: db, extProviders: ext, coolDown: coolDown, @@ -138,7 +137,7 @@ func (s *HoldersScanner) getTokensToScan() error { } }() qtx := s.db.QueriesRW.WithTx(tx) - s.tokens = []*state.TokenHolders{} + s.tokens = []*TokenHolders{} // get last created tokens from the database to scan them first lastNotSyncedTokens, err := qtx.ListLastNoSyncedTokens(ctx) if err != nil && !errors.Is(sql.ErrNoRows, err) { @@ -147,11 +146,31 @@ func (s *HoldersScanner) getTokensToScan() error { // parse last not synced token addresses for _, token := range lastNotSyncedTokens { lastBlock := uint64(token.CreationBlock) - if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil { + if lastBlock == 0 { + if networkEndpoint, ok := s.w3p.EndpointByChainID(token.ChainID); ok { + client, err := networkEndpoint.GetClient(web3.DefaultMaxWeb3ClientRetries) + if err != nil { + return err + } + web3Provider := &web3.ERC20HolderProvider{ + HexAddress: common.Bytes2Hex(token.ID), + ChainID: token.ChainID, + Client: client, + } + if err := web3Provider.Init(); err != nil { + return err + } + lastBlock, err = web3Provider.CreationBlock(ctx, nil) + if err != nil { + return err + } + } + } + if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil && blockNumber > lastBlock { lastBlock = blockNumber } - s.tokens = append(s.tokens, new(state.TokenHolders).Init( - common.BytesToAddress(token.ID), state.TokenType(token.TypeID), + s.tokens = append(s.tokens, new(TokenHolders).Init( + common.BytesToAddress(token.ID), token.TypeID, lastBlock, token.ChainID, token.ExternalID)) } // get old tokens from the database @@ -184,11 +203,31 @@ func (s *HoldersScanner) getTokensToScan() error { // parse old not synced token addresses for _, token := range oldNotSyncedTokens { lastBlock := uint64(token.CreationBlock) - if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil { + if lastBlock == 0 { + if networkEndpoint, ok := s.w3p.EndpointByChainID(token.ChainID); ok { + client, err := networkEndpoint.GetClient(web3.DefaultMaxWeb3ClientRetries) + if err != nil { + return err + } + web3Provider := &web3.ERC20HolderProvider{ + HexAddress: common.Bytes2Hex(token.ID), + ChainID: token.ChainID, + Client: client, + } + if err := web3Provider.Init(); err != nil { + return err + } + lastBlock, err = web3Provider.CreationBlock(ctx, nil) + if err != nil { + return err + } + } + } + if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil && blockNumber > lastBlock { lastBlock = blockNumber } - s.tokens = append(s.tokens, new(state.TokenHolders).Init( - common.BytesToAddress(token.ID), state.TokenType(token.TypeID), + s.tokens = append(s.tokens, new(TokenHolders).Init( + common.BytesToAddress(token.ID), token.TypeID, lastBlock, token.ChainID, token.ExternalID)) } // get last created tokens from the database to scan them first @@ -198,11 +237,31 @@ func (s *HoldersScanner) getTokensToScan() error { } for _, token := range syncedTokens { lastBlock := uint64(token.CreationBlock) - if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil { + if lastBlock == 0 { + if networkEndpoint, ok := s.w3p.EndpointByChainID(token.ChainID); ok { + client, err := networkEndpoint.GetClient(web3.DefaultMaxWeb3ClientRetries) + if err != nil { + return err + } + web3Provider := &web3.ERC20HolderProvider{ + HexAddress: common.Bytes2Hex(token.ID), + ChainID: token.ChainID, + Client: client, + } + if err := web3Provider.Init(); err != nil { + return err + } + lastBlock, err = web3Provider.CreationBlock(ctx, nil) + if err != nil { + return err + } + } + } + if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil && blockNumber > lastBlock { lastBlock = blockNumber } - s.tokens = append(s.tokens, new(state.TokenHolders).Init( - common.BytesToAddress(token.ID), state.TokenType(token.TypeID), + s.tokens = append(s.tokens, new(TokenHolders).Init( + common.BytesToAddress(token.ID), token.TypeID, lastBlock, token.ChainID, token.ExternalID)) } return nil @@ -212,7 +271,7 @@ func (s *HoldersScanner) getTokensToScan() error { // TokenHolders state provided. Updates the holders for associated token and // the blocks scanned. To do this, it requires the root hash and the timestampt // of the given TokenHolders state block. -func (s *HoldersScanner) saveHolders(th *state.TokenHolders) error { +func (s *HoldersScanner) saveHolders(th *TokenHolders) error { log.Debugw("saving token holders", "token", th.Address(), "chainID", th.ChainID, @@ -276,18 +335,26 @@ func (s *HoldersScanner) saveHolders(th *state.TokenHolders) error { if !exists { return fmt.Errorf("chain ID not supported") } + client, err := w3Endpoint.GetClient(web3.DefaultMaxWeb3ClientRetries) + if err != nil { + return err + } // init web3 contract state - w3 := state.Web3{} - if err := w3.Init(ctx, w3Endpoint, th.Address(), th.Type()); err != nil { + w3Provider := web3.ERC20HolderProvider{ + HexAddress: th.Address().Hex(), + ChainID: th.ChainID, + Client: client, + } + if err := w3Provider.Init(); err != nil { return err } // get current block number timestamp and root hash, required parameters to // create a new block in the database - timestamp, err = w3.BlockTimestamp(ctx, uint(th.LastBlock())) + timestamp, err = w3Provider.BlockTimestamp(ctx, th.LastBlock()) if err != nil { return err } - rootHash, err = w3.BlockRootHash(ctx, uint(th.LastBlock())) + rootHash, err = w3Provider.BlockRootHash(ctx, th.LastBlock()) if err != nil { return err } @@ -407,13 +474,13 @@ func (s *HoldersScanner) saveHolders(th *state.TokenHolders) error { // a new one and caches it getting the token information from the database. func (s *HoldersScanner) cachedToken(ctx context.Context, addr common.Address, chainID uint64, externalID []byte, -) (*state.TokenHolders, error) { +) (*TokenHolders, error) { // get the token TokenHolders struct from cache, if it not exists it will // be initialized s.mutex.RLock() defer s.mutex.RUnlock() - var th *state.TokenHolders + var th *TokenHolders for index, token := range s.tokens { if bytes.Equal(token.Address().Bytes(), addr.Bytes()) && token.ChainID == chainID && bytes.Equal([]byte(token.ExternalID), externalID) { @@ -448,12 +515,12 @@ func (s *HoldersScanner) cachedToken(ctx context.Context, addr common.Address, if err != nil { return nil, err } - ttype := state.TokenType(tokenInfo.TypeID) + ttype := tokenInfo.TypeID tokenLastBlock := uint64(tokenInfo.CreationBlock) if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, addr.Bytes()); err == nil { tokenLastBlock = blockNumber } - th = new(state.TokenHolders).Init(addr, ttype, tokenLastBlock, tokenInfo.ChainID, tokenInfo.ExternalID) + th = new(TokenHolders).Init(addr, ttype, tokenLastBlock, tokenInfo.ChainID, tokenInfo.ExternalID) tokenHolders, err := s.db.QueriesRO.TokenHoldersByTokenIDAndChainIDAndExternalID(ctx, queries.TokenHoldersByTokenIDAndChainIDAndExternalIDParams{ TokenID: addr.Bytes(), @@ -488,12 +555,6 @@ func (s *HoldersScanner) scanHolders(ctx context.Context, addr common.Address, c if err != nil { return false, err } - // If the last block of the current scanner is lower than the TokenHolders - // state block, it seems that the current scanner is out of date and can - // move on to this block - if s.lastBlock < th.LastBlock() { - s.lastBlock = th.LastBlock() - } // if the token type has a external provider associated, get the holders // from it and append it to the TokenHolders struct, then save it into the // database and return @@ -501,18 +562,14 @@ func (s *HoldersScanner) scanHolders(ctx context.Context, addr common.Address, c if err := provider.SetLastBalances(ctx, []byte(th.ExternalID), th.Holders(), th.LastBlock()); err != nil { return false, err } - externalBalances, err := provider.HoldersBalances(ctx, []byte(th.ExternalID), s.lastBlock-th.LastBlock()) + externalBalances, lastBlock, err := provider.HoldersBalances(ctx, []byte(th.ExternalID), s.lastBlock-th.LastBlock()) if err != nil { return false, err } for holder, balance := range externalBalances { th.Append(holder, balance) } - blockNumber, err := provider.LatestBlockNumber(ctx, []byte(th.ExternalID)) - if err != nil { - return false, err - } - th.BlockDone(blockNumber) + th.BlockDone(lastBlock) th.Synced() return true, s.saveHolders(th) } @@ -521,34 +578,31 @@ func (s *HoldersScanner) scanHolders(ctx context.Context, addr common.Address, c if !exists { return false, fmt.Errorf("chain ID not supported") } + client, err := w3URI.GetClient(web3.DefaultMaxWeb3ClientRetries) + if err != nil { + return false, err + } // init web3 contract state - w3 := state.Web3{} - if err := w3.Init(ctx, w3URI, addr, th.Type()); err != nil { - return th.IsSynced(), err + // TODO: switch between token types + web3Provider := &web3.ERC20HolderProvider{ + HexAddress: addr.Hex(), + ChainID: chainID, + Client: client, } - // try to update the TokenHolders struct and the current scanner last block - if _, err := w3.UpdateTokenHolders(ctx, th); err != nil { - if strings.Contains(err.Error(), "no new blocks") { - // if no new blocks error raises, log it as debug and return nil - log.Debugw("no new blocks to scan", "token", th.Address()) - return true, nil - } - if strings.Contains(err.Error(), "connection reset") || - strings.Contains(err.Error(), "context deadline") || - strings.Contains(err.Error(), "read limit exceeded") || - strings.Contains(err.Error(), "limit reached") { - // if connection error raises, log it as warning and try to save - // current TokenHolders state and return nil - log.Warnw("warning scanning contract", "token", th.Address().Hex(), - "block", th.LastBlock(), "error", err) - // save TokesHolders state into the database before exit of the function - return th.IsSynced(), s.saveHolders(th) - } - // if unexpected error raises, log it as error and return it. - log.Errorw(fmt.Errorf("warning scanning contract: %v", err), - fmt.Sprintf("token=%s block%d", th.Address().Hex(), th.LastBlock())) + if err := web3Provider.Init(); err != nil { return th.IsSynced(), err } + if err := web3Provider.SetLastBalances(ctx, nil, th.Holders(), th.LastBlock()); err != nil { + return false, err + } + latestBalances, lastBlock, err := web3Provider.HoldersBalances(ctx, nil, th.LastBlock()) + if err != nil { + return false, err + } + for holder, balance := range latestBalances { + th.Append(holder, balance) + } + th.BlockDone(lastBlock) // save TokesHolders state into the database before exit of the function return th.IsSynced(), s.saveHolders(th) } @@ -574,19 +628,26 @@ func (s *HoldersScanner) calcTokenCreationBlock(ctx context.Context, index int) if err != nil { return fmt.Errorf("error getting token from database: %w", err) } - ttype := state.TokenType(tokenInfo.TypeID) // get correct web3 uri provider w3URI, exists := s.w3p.EndpointByChainID(tokenInfo.ChainID) if !exists { return fmt.Errorf("chain ID not supported") } // init web3 contract state - w3 := state.Web3{} - if err := w3.Init(ctx, w3URI, addr, ttype); err != nil { + client, err := w3URI.GetClient(web3.DefaultMaxWeb3ClientRetries) + if err != nil { + return fmt.Errorf("error getting web3 client: %w", err) + } + web3Provider := &web3.ERC20HolderProvider{ + HexAddress: addr.Hex(), + ChainID: chainID, + Client: client, + } + if err := web3Provider.Init(); err != nil { return fmt.Errorf("error intializing web3 client for this token: %w", err) } // get creation block of the current token contract - creationBlock, err := w3.ContractCreationBlock(ctx) + creationBlock, err := web3Provider.CreationBlock(ctx, nil) if err != nil { return fmt.Errorf("error getting token creation block: %w", err) } diff --git a/service/poap/poap_provider.go b/service/poap/poap_provider.go index e3fd39d7..bfb29d89 100644 --- a/service/poap/poap_provider.go +++ b/service/poap/poap_provider.go @@ -11,6 +11,7 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" + "github.com/vocdoni/census3/service/web3" "go.vocdoni.io/dvote/log" ) @@ -27,7 +28,7 @@ const ( POAP_URI = "/event/%s/poaps" // POAP_CONTRACT_ADDRESS is the address of the POAP contract. POAP_CONTRACT_ADDRESS = "0x22c1f6050e56d2876009903609a2cc3fef83b415" - POAP_CONTRACT_TYPE = uint64(10000) + POAP_CONTRACT_TYPE = web3.CONTRACT_TYPE_POAP ) // EventAPIResponse is the struct that stores the response of the POAP API @@ -100,13 +101,13 @@ func (p *POAPHolderProvider) SetLastBalances(_ context.Context, id []byte, // and delta point in time. It requests the list of token holders to the POAP // API parsing every POAP holder for the event ID provided and calculate the // balances of the token holders from the last snapshot. -func (p *POAPHolderProvider) HoldersBalances(_ context.Context, id []byte, delta uint64) (map[common.Address]*big.Int, error) { +func (p *POAPHolderProvider) HoldersBalances(_ context.Context, id []byte, delta uint64) (map[common.Address]*big.Int, uint64, error) { // parse eventID from id eventID := string(id) // get last snapshot newSnapshot, err := p.lastHolders(eventID) if err != nil { - return nil, err + return nil, 0, err } // calculate snapshot from from := delta @@ -123,7 +124,7 @@ func (p *POAPHolderProvider) HoldersBalances(_ context.Context, id []byte, delta snapshot: newSnapshot, } // return partials from last snapshot - return partialBalances, nil + return partialBalances, from, nil } // Close method is not implemented in the POAP external provider. By default it diff --git a/service/tokenholders.go b/service/tokenholders.go new file mode 100644 index 00000000..a64ca089 --- /dev/null +++ b/service/tokenholders.go @@ -0,0 +1,140 @@ +package service + +import ( + "math/big" + "sync" + "sync/atomic" + + "github.com/ethereum/go-ethereum/common" +) + +type HoldersCandidates map[common.Address]*big.Int + +// TokenHolders struct abstracts the current state of a TokenHolders into the +// Census3 HoldersScanner for a specific token. It contains some information +// about the token such as its address or its type. Also includes some atomic +// variables used to store the state of the token holders safely across +// differents goroutines, such as holders list, analyzed blocks or the last +// block analyzed. +type TokenHolders struct { + address common.Address + ctype uint64 + holders sync.Map + blocks sync.Map + lastBlock atomic.Uint64 + synced atomic.Bool + ChainID uint64 + ExternalID string +} + +// Init function fills the given TokenHolders struct with the address and type +// given, also checks the block number provided as done. It returns the +// TokenHolders struct updated. +func (h *TokenHolders) Init(addr common.Address, ctype uint64, block, chainID uint64, externalID string) *TokenHolders { + h.address = addr + h.ctype = ctype + h.holders = sync.Map{} + h.blocks = sync.Map{} + h.lastBlock.Store(block) + h.synced.Store(false) + h.ChainID = chainID + h.ExternalID = externalID + return h +} + +// Address function returns the given TokenHolders token address. +func (h *TokenHolders) Address() common.Address { + return h.address +} + +// Type function returns the given TokenHolders token type. +func (h *TokenHolders) Type() uint64 { + return h.ctype +} + +// IsReady function returns if the given TokenHolders is ready to be scanned. +// It means that the last block number is greater than 0, at least it will be +// the creation block of the token. +func (h *TokenHolders) IsReady() bool { + return h.lastBlock.Load() > 0 +} + +// Holders function returns the given TokenHolders current token holders +// addresses and its balances. +func (h *TokenHolders) Holders() HoldersCandidates { + holders := HoldersCandidates{} + h.holders.Range(func(rawAddr, rawBalance any) bool { + address, okAddr := rawAddr.(common.Address) + balance, okBalance := rawBalance.(*big.Int) + if !okAddr || !okBalance { + return true + } + + holders[address] = balance + return true + }) + return holders +} + +// Exists function returns if the given TokenHolders list of holders addresss +// includes the provided address. +func (h *TokenHolders) Exists(address common.Address) bool { + _, exists := h.holders.Load(address) + return exists +} + +// Append function appends the holder address and the balance provided into the +// given TokenHolders list of holders. If the holder already exists, it will +// update its balance. +func (h *TokenHolders) Append(addr common.Address, balance *big.Int) { + if currentBalance, exists := h.holders.Load(addr); exists { + h.holders.Store(addr, new(big.Int).Add(currentBalance.(*big.Int), balance)) + return + } + h.holders.Store(addr, balance) +} + +// Del function marks the holder address provided in the list of current +// TokenHolders as false, which means that it will be removed. +func (h *TokenHolders) Del(address common.Address) { + h.holders.Store(address, false) +} + +// FlushHolders function cleans the current list of token holders from the +// current TokenHolders state. +func (h *TokenHolders) FlushHolders() { + h.holders = sync.Map{} +} + +// BlockDone function checks the block number provided as checked appending it +// to the given TokenHolders list of blocks. If it is greater than the current +// TokenHolders block number, it will be updated. +func (h *TokenHolders) BlockDone(blockNumber uint64) { + h.blocks.Store(blockNumber, true) + h.synced.Store(false) + h.lastBlock.CompareAndSwap(h.lastBlock.Load(), blockNumber) +} + +// HasBlock function returns if the provided block number has already checked by +// the given TokenHolders. +func (h *TokenHolders) HasBlock(blockNumber uint64) bool { + _, exists := h.blocks.Load(blockNumber) + return exists +} + +// LastBlock function returns the number of latest block registered. +func (h *TokenHolders) LastBlock() uint64 { + return h.lastBlock.Load() +} + +// Synced function marks the current TokenHolders struct as synced with the +// latest network status. +func (h *TokenHolders) Synced() { + h.synced.Store(true) +} + +// IsSynced function returns if the current TokenHolders instance is already +// synced with the latest network status. +func (h *TokenHolders) IsSynced() bool { + return h.synced.Load() +} diff --git a/service/tokenholders_test.go b/service/tokenholders_test.go new file mode 100644 index 00000000..d0dbb41f --- /dev/null +++ b/service/tokenholders_test.go @@ -0,0 +1,137 @@ +package service + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + qt "github.com/frankban/quicktest" + "github.com/vocdoni/census3/service/web3" +) + +func TestTokenHoldersInit(t *testing.T) { + c := qt.New(t) + th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 0, "") + c.Assert(th.address.String(), qt.Equals, MonkeysAddress.String()) + c.Assert(th.ctype, qt.Equals, web3.CONTRACT_TYPE_ERC20) + c.Assert(th.lastBlock.Load(), qt.Equals, MonkeysCreationBlock) + c.Assert(th.synced.Load(), qt.IsFalse) +} + +func TestHolders(t *testing.T) { + c := qt.New(t) + th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + c.Assert(th.address.String(), qt.Equals, MonkeysAddress.String()) + c.Assert(th.ctype, qt.Equals, web3.CONTRACT_TYPE_ERC20) + c.Assert(th.lastBlock.Load(), qt.Equals, MonkeysCreationBlock) + c.Assert(th.synced.Load(), qt.IsFalse) +} + +func TestAppend(t *testing.T) { + c := qt.New(t) + th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + + holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") + holderBalance := new(big.Int).SetUint64(16000000000000000000) + _, exists := th.holders.Load(holderAddr) + c.Assert(exists, qt.IsFalse) + th.Append(holderAddr, holderBalance) + balance, exists := th.holders.Load(holderAddr) + c.Assert(exists, qt.IsTrue) + c.Assert(balance.(*big.Int).String(), qt.Equals, holderBalance.String()) +} + +func TestExists(t *testing.T) { + c := qt.New(t) + th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + + holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") + holderBalance := new(big.Int).SetUint64(16000000000000000000) + c.Assert(th.Exists(holderAddr), qt.IsFalse) + th.Append(holderAddr, holderBalance) + c.Assert(th.Exists(holderAddr), qt.IsTrue) +} + +func TestDel(t *testing.T) { + c := qt.New(t) + th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + + holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") + holderBalance := new(big.Int).SetUint64(16000000000000000000) + th.Append(holderAddr, holderBalance) + balance, exists := th.holders.Load(holderAddr) + c.Assert(exists, qt.IsTrue) + c.Assert(balance.(*big.Int).String(), qt.Equals, holderBalance.String()) + + th.Del(holderAddr) + notRemove, exists := th.holders.Load(holderAddr) + c.Assert(exists, qt.IsTrue) + c.Assert(notRemove.(bool), qt.IsFalse) +} + +func TestFlushHolders(t *testing.T) { + c := qt.New(t) + th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + + holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") + holderBalance := new(big.Int).SetUint64(16000000000000000000) + th.Append(holderAddr, holderBalance) + balance, exists := th.holders.Load(holderAddr) + c.Assert(exists, qt.IsTrue) + c.Assert(balance.(*big.Int).String(), qt.Equals, holderBalance.String()) + + th.FlushHolders() + _, exists = th.holders.Load(holderAddr) + c.Assert(exists, qt.IsFalse) +} + +func TestBlockDone(t *testing.T) { + c := qt.New(t) + th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + + _, exists := th.blocks.Load(MonkeysCreationBlock + 500) + c.Assert(exists, qt.IsFalse) + + th.BlockDone(MonkeysCreationBlock + 500) + processed, exists := th.blocks.Load(MonkeysCreationBlock + 500) + c.Assert(exists, qt.IsTrue) + c.Assert(processed.(bool), qt.IsTrue) +} + +func TestHasBlock(t *testing.T) { + c := qt.New(t) + th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + + c.Assert(th.HasBlock(MonkeysCreationBlock), qt.IsFalse) + th.BlockDone(MonkeysCreationBlock) + c.Assert(th.HasBlock(MonkeysCreationBlock), qt.IsTrue) +} + +func TestLastBlock(t *testing.T) { + c := qt.New(t) + th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + + c.Assert(th.LastBlock(), qt.Equals, MonkeysCreationBlock) + th.BlockDone(MonkeysCreationBlock + 1) + c.Assert(th.LastBlock(), qt.Equals, MonkeysCreationBlock+1) + th.BlockDone(MonkeysCreationBlock + 2) + c.Assert(th.LastBlock(), qt.Equals, MonkeysCreationBlock+2) +} + +func TestSynced(t *testing.T) { + c := qt.New(t) + th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + + c.Assert(th.synced.Load(), qt.IsFalse) + th.Synced() + c.Assert(th.synced.Load(), qt.IsTrue) +} + +func TestIsSynced(t *testing.T) { + c := qt.New(t) + th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + + c.Assert(th.IsSynced(), qt.IsFalse) + th.Synced() + c.Assert(th.IsSynced(), qt.IsTrue) +} diff --git a/service/web3/const.go b/service/web3/const.go index bf274d06..a72fa605 100644 --- a/service/web3/const.go +++ b/service/web3/const.go @@ -39,11 +39,9 @@ const ( // Add more topics here ) -type TokenType uint64 - const ( // CONTRACT TYPES - CONTRACT_TYPE_UNKNOWN TokenType = iota + CONTRACT_TYPE_UNKNOWN uint64 = iota CONTRACT_TYPE_ERC20 CONTRACT_TYPE_ERC721 CONTRACT_TYPE_ERC1155 @@ -51,4 +49,29 @@ const ( CONTRACT_TYPE_CUSTOM_NATION3_VENATION CONTRACT_TYPE_CUSTOM_ARAGON_WANT CONTRACT_TYPE_ERC721_BURNED + CONTRACT_TYPE_POAP ) + +var TokenTypeStringMap = map[uint64]string{ + CONTRACT_TYPE_UNKNOWN: "unknown", + CONTRACT_TYPE_ERC20: "erc20", + CONTRACT_TYPE_ERC721_BURNED: "erc721burned", + CONTRACT_TYPE_ERC1155: "erc1155", + CONTRACT_TYPE_ERC777: "erc777", + CONTRACT_TYPE_CUSTOM_NATION3_VENATION: "nation3", + CONTRACT_TYPE_CUSTOM_ARAGON_WANT: "want", + CONTRACT_TYPE_ERC721: "erc721", + CONTRACT_TYPE_POAP: "poap", +} + +var TokenTypeIntMap = map[string]uint64{ + "unknown": CONTRACT_TYPE_UNKNOWN, + "erc20": CONTRACT_TYPE_ERC20, + "erc721": CONTRACT_TYPE_ERC721, + "erc1155": CONTRACT_TYPE_ERC1155, + "erc777": CONTRACT_TYPE_ERC777, + "nation3": CONTRACT_TYPE_CUSTOM_NATION3_VENATION, + "want": CONTRACT_TYPE_CUSTOM_ARAGON_WANT, + "erc721burned": CONTRACT_TYPE_ERC721_BURNED, + "poap": CONTRACT_TYPE_POAP, +} diff --git a/service/web3/erc20_provider.go b/service/web3/erc20_provider.go index 2f36b3a9..bd53e43e 100644 --- a/service/web3/erc20_provider.go +++ b/service/web3/erc20_provider.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" erc20 "github.com/vocdoni/census3/contracts/erc/erc20" + "go.vocdoni.io/dvote/log" ) type ERC20HolderProvider struct { @@ -61,22 +62,29 @@ func (p *ERC20HolderProvider) SetLastBalances(ctx context.Context, id []byte, ba return nil } -func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, _ uint64) (map[common.Address]*big.Int, error) { +func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fromBlock uint64) (map[common.Address]*big.Int, uint64, error) { // calculate the range of blocks to scan, by default take the last block // scanned and scan to the latest block - fromBlock := p.balancesBlock toBlock, err := p.LatestBlockNumber(ctx, nil) if err != nil { - return nil, err + return nil, fromBlock, err } // if the range is too big, scan only a part of it using the constant // BLOCKS_TO_SCAN_AT_ONCE if toBlock > fromBlock+BLOCKS_TO_SCAN_AT_ONCE { toBlock = fromBlock + BLOCKS_TO_SCAN_AT_ONCE } + log.Infow("scanning ERC20 logs", + "fromBlock", fromBlock, + "toBlock", toBlock, + "address", p.address.Hex()) // iterate scanning the logs in the range of blocks until the last block // is reached + totalLogs := 0 for fromBlock < toBlock { + if totalLogs > MAX_SCAN_LOGS_PER_ITERATION { + return p.balances, toBlock, nil + } // compose the filter to get the logs of the ERC20 Transfer events filter := ethereum.FilterQuery{ Addresses: []common.Address{p.address}, @@ -95,13 +103,19 @@ func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, _ u toBlock = fromBlock + ((toBlock - fromBlock) / 2) continue } - return nil, errors.Join(ErrScanningTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.HexAddress, err)) + return nil, fromBlock, errors.Join(ErrScanningTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.HexAddress, err)) + } + // if there are no logs, the range of blocks is empty, so return the + // balances + if len(logs) == 0 { + return p.balances, toBlock, nil } + totalLogs += len(logs) // iterate the logs and update the balances for _, log := range logs { logData, err := p.contract.ERC20ContractFilterer.ParseTransfer(log) if err != nil { - return nil, errors.Join(ErrParsingTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.HexAddress, err)) + return nil, log.BlockNumber, errors.Join(ErrParsingTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.HexAddress, err)) } // update balances p.balancesMtx.Lock() @@ -118,7 +132,7 @@ func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, _ u p.balancesMtx.Unlock() } } - return p.balances, nil + return p.balances, toBlock, nil } func (p *ERC20HolderProvider) Close() error { @@ -129,7 +143,7 @@ func (p *ERC20HolderProvider) Address() common.Address { return p.address } -func (p *ERC20HolderProvider) Type() TokenType { +func (p *ERC20HolderProvider) Type() uint64 { return CONTRACT_TYPE_ERC20 } @@ -202,7 +216,7 @@ func (p *ERC20HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) ( func (p *ERC20HolderProvider) CreationBlock(ctx context.Context, _ []byte) (uint64, error) { var err error - if p.creationBlock != 0 { + if p.creationBlock == 0 { var lastBlock uint64 lastBlock, err = p.LatestBlockNumber(ctx, nil) if err != nil { diff --git a/service/web3/helpers.go b/service/web3/helpers.go index 16c9da46..bb24d2ee 100644 --- a/service/web3/helpers.go +++ b/service/web3/helpers.go @@ -10,6 +10,13 @@ import ( "github.com/ethereum/go-ethereum/ethclient" ) +func TokenTypeFromString(s string) uint64 { + if c, ok := TokenTypeIntMap[s]; ok { + return c + } + return CONTRACT_TYPE_UNKNOWN +} + // creationBlockInRange function finds the block number of a contract between // the bounds provided as start and end blocks. func creationBlockInRange(client *ethclient.Client, ctx context.Context, addr common.Address, start, end uint64) (uint64, error) { From 303c767a2728905ef1241d2a5cc259e89781ce22 Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Wed, 17 Jan 2024 11:27:47 +0100 Subject: [PATCH 03/35] clean version of ERC20 holder provider, merged with external providers --- api/api.go | 50 +- api/censuses.go | 2 +- api/helpers.go | 25 +- api/holders.go | 26 +- api/strategies.go | 2 +- api/tokens.go | 54 +- cmd/census3/main.go | 41 +- service/holder_scanner_test.go | 17 +- service/holders_scanner.go | 245 ++----- service/{ => providers}/holders_provider.go | 13 +- service/{ => providers}/poap/poap_provider.go | 48 +- .../poap/poap_provider_test.go | 0 service/providers/types.go | 38 + {state => service/providers/web3}/const.go | 41 +- service/{ => providers}/web3/endpoint.go | 0 service/{ => providers}/web3/endpoint_test.go | 0 service/providers/web3/erc20_provider.go | 309 ++++++++ service/providers/web3/errors.go | 11 + service/{ => providers}/web3/helpers.go | 5 +- service/providers/web3/web3_provider.go | 11 + service/tokenholders_test.go | 28 +- service/web3/const.go | 77 -- service/web3/erc20_provider.go | 232 ------ service/web3/errors.go | 10 - state/README.md | 7 - state/helper_test.go | 30 - state/holders.go | 140 ---- state/holders_test.go | 136 ---- state/mod_tidy_workaround.go | 5 - state/tokens.go | 63 -- state/tokens_test.go | 25 - state/web3.go | 671 ------------------ state/web3_test.go | 326 --------- 33 files changed, 639 insertions(+), 2049 deletions(-) rename service/{ => providers}/holders_provider.go (84%) rename service/{ => providers}/poap/poap_provider.go (92%) rename service/{ => providers}/poap/poap_provider_test.go (100%) create mode 100644 service/providers/types.go rename {state => service/providers/web3}/const.go (67%) rename service/{ => providers}/web3/endpoint.go (100%) rename service/{ => providers}/web3/endpoint_test.go (100%) create mode 100644 service/providers/web3/erc20_provider.go create mode 100644 service/providers/web3/errors.go rename service/{ => providers}/web3/helpers.go (92%) create mode 100644 service/providers/web3/web3_provider.go delete mode 100644 service/web3/const.go delete mode 100644 service/web3/erc20_provider.go delete mode 100644 service/web3/errors.go delete mode 100644 state/README.md delete mode 100644 state/helper_test.go delete mode 100644 state/holders.go delete mode 100644 state/holders_test.go delete mode 100644 state/mod_tidy_workaround.go delete mode 100644 state/tokens.go delete mode 100644 state/tokens_test.go delete mode 100644 state/web3.go delete mode 100644 state/web3_test.go diff --git a/api/api.go b/api/api.go index 7718fdc0..f0b6629b 100644 --- a/api/api.go +++ b/api/api.go @@ -7,8 +7,8 @@ import ( lru "github.com/hashicorp/golang-lru/v2" "github.com/vocdoni/census3/db" "github.com/vocdoni/census3/queue" - "github.com/vocdoni/census3/service" - "github.com/vocdoni/census3/service/web3" + "github.com/vocdoni/census3/service/providers" + "github.com/vocdoni/census3/service/providers/web3" "go.vocdoni.io/dvote/api/censusdb" storagelayer "go.vocdoni.io/dvote/data" "go.vocdoni.io/dvote/data/downloader" @@ -23,26 +23,26 @@ import ( ) type Census3APIConf struct { - Hostname string - Port int - DataDir string - GroupKey string - Web3Providers web3.NetworkEndpoints - ExtProviders map[uint64]service.HolderProvider - AdminToken string + Hostname string + Port int + DataDir string + GroupKey string + Web3Providers web3.NetworkEndpoints + HolderProviders map[uint64]providers.HolderProvider + AdminToken string } type census3API struct { - conf Census3APIConf - db *db.DB - endpoint *api.API - censusDB *censusdb.CensusDB - queue *queue.BackgroundQueue - w3p web3.NetworkEndpoints - storage storagelayer.Storage - downloader *downloader.Downloader - extProviders map[uint64]service.HolderProvider - cache *lru.Cache[CacheKey, any] + conf Census3APIConf + db *db.DB + endpoint *api.API + censusDB *censusdb.CensusDB + queue *queue.BackgroundQueue + w3p web3.NetworkEndpoints + storage storagelayer.Storage + downloader *downloader.Downloader + holderProviders map[uint64]providers.HolderProvider + cache *lru.Cache[CacheKey, any] } func Init(db *db.DB, conf Census3APIConf) (*census3API, error) { @@ -51,12 +51,12 @@ func Init(db *db.DB, conf Census3APIConf) (*census3API, error) { return nil, err } newAPI := &census3API{ - conf: conf, - db: db, - w3p: conf.Web3Providers, - queue: queue.NewBackgroundQueue(), - extProviders: conf.ExtProviders, - cache: cache, + conf: conf, + db: db, + w3p: conf.Web3Providers, + queue: queue.NewBackgroundQueue(), + holderProviders: conf.HolderProviders, + cache: cache, } // get the current chainID log.Infow("starting API", "web3Providers", conf.Web3Providers.String()) diff --git a/api/censuses.go b/api/censuses.go index b62e4fe4..de40f7b5 100644 --- a/api/censuses.go +++ b/api/censuses.go @@ -140,7 +140,7 @@ func (capi *census3API) createAndPublishCensus(req *CreateCensusRequest, qID str } // init some variables to get computed in the following steps strategyHolders, censusWeight, totalTokensBlockNumber, err := CalculateStrategyHolders( - internalCtx, capi.db.QueriesRO, capi.w3p, req.StrategyID, strategy.Predicate) + internalCtx, capi.db.QueriesRO, capi.holderProviders, req.StrategyID, strategy.Predicate) if err != nil { return 0, ErrEvalStrategyPredicate.WithErr(err) } diff --git a/api/helpers.go b/api/helpers.go index 92bf2092..7b46a3a3 100644 --- a/api/helpers.go +++ b/api/helpers.go @@ -14,8 +14,8 @@ import ( "github.com/ethereum/go-ethereum/common" queries "github.com/vocdoni/census3/db/sqlc" "github.com/vocdoni/census3/lexer" - "github.com/vocdoni/census3/service/web3" - "github.com/vocdoni/census3/state" + "github.com/vocdoni/census3/service/providers" + "github.com/vocdoni/census3/service/providers/web3" "github.com/vocdoni/census3/strategyoperators" "go.vocdoni.io/dvote/api/censusdb" "go.vocdoni.io/dvote/censustree" @@ -208,8 +208,8 @@ func InnerCensusID(blockNumber, strategyID uint64, anonymous bool) uint64 { // The evaluator uses the strategy operators to evaluate the predicate which // uses the database queries to get the token holders and their balances, and // combines them. -func CalculateStrategyHolders(ctx context.Context, qdb *queries.Queries, w3p web3.NetworkEndpoints, - id uint64, predicate string, +func CalculateStrategyHolders(ctx context.Context, qdb *queries.Queries, + providers map[uint64]providers.HolderProvider, id uint64, predicate string, ) (map[common.Address]*big.Int, *big.Int, uint64, error) { // TODO: write a benchmark and try to optimize this function @@ -237,15 +237,20 @@ func CalculateStrategyHolders(ctx context.Context, qdb *queries.Queries, w3p web // number, used to create the census id. totalTokensBlockNumber := uint64(0) for _, token := range strategyTokens { - w3endpoint, exists := w3p.EndpointByChainID(token.ChainID) + provider, exists := providers[token.TypeID] if !exists { - return nil, nil, 0, fmt.Errorf("web3 endpoint not found for chain id %d", token.ChainID) + return nil, nil, 0, fmt.Errorf("provider not found for token type id %d", token.TypeID) } - w3 := state.Web3{} - if err := w3.Init(ctx, w3endpoint, common.BytesToAddress(token.ID), state.TokenType(token.TypeID)); err != nil { - return nil, nil, 0, err + if !provider.IsExternal() { + if err := provider.SetRef(web3.Web3ProviderRef{ + HexAddress: common.Bytes2Hex(token.ID), + ChainID: token.ChainID, + }); err != nil { + return nil, nil, 0, err + } } - currentBlockNumber, err := w3.LatestBlockNumber(ctx) + + currentBlockNumber, err := provider.LatestBlockNumber(ctx, []byte(token.ExternalID)) if err != nil { return nil, nil, 0, err } diff --git a/api/holders.go b/api/holders.go index b969af28..057ae4fb 100644 --- a/api/holders.go +++ b/api/holders.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common" queries "github.com/vocdoni/census3/db/sqlc" - "github.com/vocdoni/census3/service/web3" + "github.com/vocdoni/census3/service/providers/web3" "go.vocdoni.io/dvote/httprouter" api "go.vocdoni.io/dvote/httprouter/apirest" "go.vocdoni.io/dvote/log" @@ -106,25 +106,25 @@ func (capi *census3API) listHoldersAtLastBlock(address common.Address, return nil, 0, ErrCantGetTokenHolders.WithErr(err) } // if the token is external, return an error - // TODO: implement external token holders - if _, isExternal := capi.extProviders[tokenData.TypeID]; isExternal { - return nil, 0, ErrCantCreateCensus.With("not implemented for external providers") - } - // get correct web3 uri provider - w3URI, exists := capi.w3p.EndpointByChainID(tokenData.ChainID) + provider, exists := capi.holderProviders[tokenData.TypeID] if !exists { - return nil, 0, ErrChainIDNotSupported.With("chain ID not supported") + return nil, 0, ErrCantCreateCensus.With("token type not supported") } - w3, err := w3URI.GetClient(web3.DefaultMaxWeb3ClientRetries) - if err != nil { + if provider.IsExternal() { + return nil, 0, ErrCantCreateCensus.With("not implemented for external providers") + } + if err := provider.SetRef(web3.Web3ProviderRef{ + HexAddress: common.Bytes2Hex(tokenData.ID), + ChainID: tokenData.ChainID, + }); err != nil { return nil, 0, ErrInitializingWeb3.WithErr(err) } + // get last block of the network - lastBlockNumber, err := w3.BlockNumber(internalCtx) + lastBlockNumber, err := provider.LatestBlockNumber(internalCtx, nil) if err != nil { return nil, 0, ErrCantGetLastBlockNumber.WithErr(err) } - bLastBlockNumber := new(big.Int).SetUint64(lastBlockNumber) // get holders balances at last block balances := make(map[string]string) for i, holder := range holders { @@ -133,7 +133,7 @@ func (capi *census3API) listHoldersAtLastBlock(address common.Address, "token", address.String(), "progress", fmt.Sprintf("%d/%d", i+1, len(holders))) holderAddress := common.BytesToAddress(holder.ID) - balance, err := w3.BalanceAt(internalCtx, holderAddress, bLastBlockNumber) + balance, err := provider.BalanceAt(internalCtx, holderAddress, nil, lastBlockNumber) if err != nil { return nil, lastBlockNumber, ErrCantGetTokenHolders.WithErr(err) } diff --git a/api/strategies.go b/api/strategies.go index c972628d..83bca999 100644 --- a/api/strategies.go +++ b/api/strategies.go @@ -662,7 +662,7 @@ func (capi *census3API) estimateStrategySizeAndAccuracy(strategyID uint64, anony } // calculate the strategy holders strategyHolders, _, _, err := CalculateStrategyHolders(internalCtx, - capi.db.QueriesRO, capi.w3p, strategyID, strategy.Predicate) + capi.db.QueriesRO, capi.holderProviders, strategyID, strategy.Predicate) if err != nil { return 0, 0, ErrEvalStrategyPredicate.WithErr(err) } diff --git a/api/tokens.go b/api/tokens.go index b96d8f22..96eed583 100644 --- a/api/tokens.go +++ b/api/tokens.go @@ -15,8 +15,8 @@ import ( queries "github.com/vocdoni/census3/db/sqlc" "github.com/vocdoni/census3/internal" "github.com/vocdoni/census3/lexer" - "github.com/vocdoni/census3/service/web3" - "github.com/vocdoni/census3/state" + "github.com/vocdoni/census3/service/providers" + "github.com/vocdoni/census3/service/providers/web3" "go.vocdoni.io/dvote/httprouter" api "go.vocdoni.io/dvote/httprouter/apirest" "go.vocdoni.io/dvote/log" @@ -114,7 +114,7 @@ func (capi *census3API) getTokens(msg *api.APIdata, ctx *httprouter.HTTPContext) for _, tokenData := range rows { tokensResponse.Tokens = append(tokensResponse.Tokens, GetTokensItemResponse{ ID: common.BytesToAddress(tokenData.ID).String(), - Type: state.TokenType(int(tokenData.TypeID)).String(), + Type: providers.TokenTypeStringMap[tokenData.TypeID], Decimals: tokenData.Decimals, Name: tokenData.Name, StartBlock: uint64(tokenData.CreationBlock), @@ -224,24 +224,17 @@ func (capi *census3API) createToken(msg *api.APIdata, ctx *httprouter.HTTPContex } internalCtx, cancel := context.WithTimeout(ctx.Request.Context(), createTokenTimeout) defer cancel() - - endpoint, ok := capi.w3p.EndpointByChainID(req.ChainID) - if !ok { - return ErrChainIDNotSupported.With("chain ID not supported") - } + // get the correct holder provider for the token type tokenType := web3.TokenTypeFromString(req.Type) - provider, isExternal := capi.extProviders[tokenType] - if !isExternal { - client, err := endpoint.GetClient(web3.DefaultMaxWeb3ClientRetries) - if err != nil { - return ErrInitializingWeb3.WithErr(err) - } - provider = &web3.ERC20HolderProvider{ + provider, exists := capi.holderProviders[tokenType] + if !exists { + return ErrCantCreateCensus.With("token type not supported") + } + if !provider.IsExternal() { + if err := provider.SetRef(web3.Web3ProviderRef{ HexAddress: req.ID, ChainID: req.ChainID, - Client: client, - } - if err := provider.Init(); err != nil { + }); err != nil { return ErrInitializingWeb3.WithErr(err) } } @@ -487,18 +480,20 @@ func (capi *census3API) getToken(msg *api.APIdata, ctx *httprouter.HTTPContext) // calculate the current scan progress tokenProgress := 100 if !tokenData.Synced { - // get correct web3 uri provider - w3URI, exists := capi.w3p.EndpointByChainID(tokenData.ChainID) + provider, exists := capi.holderProviders[tokenData.TypeID] if !exists { - return ErrChainIDNotSupported.With("chain ID not supported") + return ErrCantCreateCensus.With("token type not supported") } - // get last block of the network, if something fails return progress 0 - w3 := state.Web3{} - if err := w3.Init(internalCtx, w3URI, address, state.TokenType(tokenData.TypeID)); err != nil { - return ErrInitializingWeb3.WithErr(err) + if !provider.IsExternal() { + if err := provider.SetRef(web3.Web3ProviderRef{ + HexAddress: common.Bytes2Hex(tokenData.ID), + ChainID: tokenData.ChainID, + }); err != nil { + return ErrInitializingWeb3.WithErr(err) + } } // fetch the last block header and calculate progress - lastBlockNumber, err := w3.LatestBlockNumber(internalCtx) + lastBlockNumber, err := provider.LatestBlockNumber(internalCtx, []byte(tokenData.ExternalID)) if err != nil { return ErrCantGetLastBlockNumber.WithErr(err) } @@ -518,7 +513,7 @@ func (capi *census3API) getToken(msg *api.APIdata, ctx *httprouter.HTTPContext) // build response tokenResponse := GetTokenResponse{ ID: address.String(), - Type: state.TokenType(int(tokenData.TypeID)).String(), + Type: providers.TokenTypeStringMap[tokenData.TypeID], Decimals: tokenData.Decimals, Size: uint64(holders), Name: tokenData.Name, @@ -530,8 +525,7 @@ func (capi *census3API) getToken(msg *api.APIdata, ctx *httprouter.HTTPContext) Synced: tokenData.Synced, Progress: tokenProgress, }, - Tags: tokenData.Tags, - // TODO: Only for the MVP, consider to remove it + Tags: tokenData.Tags, DefaultStrategy: tokenData.DefaultStrategy, ChainID: tokenData.ChainID, ChainAddress: tokenData.ChainAddress, @@ -593,7 +587,7 @@ func (capi *census3API) isTokenHolder(msg *api.APIdata, ctx *httprouter.HTTPCont // supported types of token contracts. func (capi *census3API) getTokenTypes(msg *api.APIdata, ctx *httprouter.HTTPContext) error { supportedTypes := []string{} - for _, supportedType := range state.TokenTypeStringMap { + for _, supportedType := range providers.TokenTypeStringMap { supportedTypes = append(supportedTypes, supportedType) } res, err := json.Marshal(TokenTypesResponse{supportedTypes}) diff --git a/cmd/census3/main.go b/cmd/census3/main.go index 9d300a1c..23e3ed40 100644 --- a/cmd/census3/main.go +++ b/cmd/census3/main.go @@ -17,8 +17,9 @@ import ( "github.com/vocdoni/census3/db" "github.com/vocdoni/census3/internal" "github.com/vocdoni/census3/service" - "github.com/vocdoni/census3/service/poap" - "github.com/vocdoni/census3/service/web3" + "github.com/vocdoni/census3/service/providers" + "github.com/vocdoni/census3/service/providers/poap" + "github.com/vocdoni/census3/service/providers/web3" "go.vocdoni.io/dvote/log" ) @@ -116,19 +117,25 @@ func main() { if err != nil { log.Fatal(err) } + // init the ERC20 token providers + erc20Provider := new(web3.ERC20HolderProvider) + if err := erc20Provider.Init(web3.Web3ProviderConfig{Endpoints: w3p}); err != nil { + log.Fatal(err) + } // init POAP external provider - poapProvider := &poap.POAPHolderProvider{ + poapProvider := new(poap.POAPHolderProvider) + if err := poapProvider.Init(poap.POAPConfig{ URI: config.poapAPIEndpoint, AccessToken: config.poapAuthToken, - } - if err := poapProvider.Init(); err != nil { + }); err != nil { log.Fatal(err) } - // start the holder scanner with the database and the external providers - externalProviders := map[uint64]service.HolderProvider{ - web3.CONTRACT_TYPE_POAP: poapProvider, + holderProviders := map[uint64]providers.HolderProvider{ + providers.CONTRACT_TYPE_ERC20: erc20Provider, + providers.CONTRACT_TYPE_POAP: poapProvider, } - hc, err := service.NewHoldersScanner(database, w3p, externalProviders, config.scannerCoolDown) + // start the holder scanner with the database + hc, err := service.NewHoldersScanner(database, w3p, holderProviders, config.scannerCoolDown) if err != nil { log.Fatal(err) } @@ -143,13 +150,13 @@ func main() { } // Start the API apiService, err := api.Init(database, api.Census3APIConf{ - Hostname: "0.0.0.0", - Port: config.port, - DataDir: config.dataDir, - Web3Providers: w3p, - GroupKey: config.connectKey, - ExtProviders: externalProviders, - AdminToken: config.adminToken, + Hostname: "0.0.0.0", + Port: config.port, + DataDir: config.dataDir, + Web3Providers: w3p, + GroupKey: config.connectKey, + HolderProviders: holderProviders, + AdminToken: config.adminToken, }) if err != nil { log.Fatal(err) @@ -175,7 +182,7 @@ func main() { if err := database.Close(); err != nil { log.Fatal(err) } - for _, provider := range externalProviders { + for _, provider := range holderProviders { if err := provider.Close(); err != nil { log.Fatal(err) } diff --git a/service/holder_scanner_test.go b/service/holder_scanner_test.go index d0d805b7..b82316ea 100644 --- a/service/holder_scanner_test.go +++ b/service/holder_scanner_test.go @@ -11,7 +11,8 @@ import ( "github.com/ethereum/go-ethereum/common" qt "github.com/frankban/quicktest" queries "github.com/vocdoni/census3/db/sqlc" - "github.com/vocdoni/census3/service/web3" + "github.com/vocdoni/census3/service/providers" + "github.com/vocdoni/census3/service/providers/web3" ) var ( @@ -81,7 +82,7 @@ func Test_getTokensToScan(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() _, err = testdb.db.QueriesRW.CreateToken(ctx, testTokenParams("0x1", "test0", - "test0", 0, MonkeysDecimals, uint64(web3.CONTRACT_TYPE_ERC20), + "test0", 0, MonkeysDecimals, uint64(providers.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) c.Assert(err, qt.IsNil) @@ -91,7 +92,7 @@ func Test_getTokensToScan(t *testing.T) { c.Assert(hs.tokens[0].Address().String(), qt.Equals, common.HexToAddress("0x1").String()) _, err = testdb.db.QueriesRW.CreateToken(ctx, testTokenParams("0x2", "test2", - "test3", 10, MonkeysDecimals, uint64(web3.CONTRACT_TYPE_ERC20), + "test3", 10, MonkeysDecimals, uint64(providers.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) c.Assert(err, qt.IsNil) @@ -110,12 +111,12 @@ func Test_saveHolders(t *testing.T) { hs, err := NewHoldersScanner(testdb.db, web3Endpoints, nil, 20) c.Assert(err, qt.IsNil) - th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") // no registered token c.Assert(hs.saveHolders(th), qt.ErrorIs, ErrTokenNotExists) _, err = testdb.db.QueriesRW.CreateToken(context.Background(), testTokenParams( MonkeysAddress.String(), MonkeysName, MonkeysSymbol, MonkeysCreationBlock, - MonkeysDecimals, uint64(web3.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) + MonkeysDecimals, uint64(providers.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) c.Assert(err, qt.IsNil) // check no new holders c.Assert(hs.saveHolders(th), qt.IsNil) @@ -176,7 +177,7 @@ func Test_scanHolders(t *testing.T) { _, err = testdb.db.QueriesRW.CreateToken(context.Background(), testTokenParams( MonkeysAddress.String(), MonkeysName, MonkeysSymbol, MonkeysCreationBlock, - MonkeysDecimals, uint64(web3.CONTRACT_TYPE_ERC20), 10, false, 5, "")) + MonkeysDecimals, uint64(providers.CONTRACT_TYPE_ERC20), 10, false, 5, "")) c.Assert(err, qt.IsNil) // token exists and the scanner gets the holders ctx2, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -202,13 +203,13 @@ func Test_calcTokenCreationBlock(t *testing.T) { defer testdb.Close(t) hs, err := NewHoldersScanner(testdb.db, web3Endpoints, nil, 20) - hs.tokens = append(hs.tokens, new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, 0, 5, "")) + hs.tokens = append(hs.tokens, new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, 0, 5, "")) c.Assert(err, qt.IsNil) c.Assert(hs.calcTokenCreationBlock(context.Background(), 5), qt.IsNotNil) _, err = testdb.db.QueriesRW.CreateToken(context.Background(), testTokenParams( MonkeysAddress.String(), MonkeysName, MonkeysSymbol, MonkeysCreationBlock, - MonkeysDecimals, uint64(web3.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) + MonkeysDecimals, uint64(providers.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) c.Assert(err, qt.IsNil) c.Assert(hs.calcTokenCreationBlock(context.Background(), 0), qt.IsNil) diff --git a/service/holders_scanner.go b/service/holders_scanner.go index 82737c75..226d2d16 100644 --- a/service/holders_scanner.go +++ b/service/holders_scanner.go @@ -17,7 +17,8 @@ import ( "github.com/vocdoni/census3/db" queries "github.com/vocdoni/census3/db/sqlc" - "github.com/vocdoni/census3/service/web3" + "github.com/vocdoni/census3/service/providers" + "github.com/vocdoni/census3/service/providers/web3" "go.vocdoni.io/dvote/log" ) @@ -31,31 +32,31 @@ var ( // the tokens stored on the database (located on 'dataDir/dbFilename'). It // keeps the database updated scanning the network using the web3 endpoint. type HoldersScanner struct { - w3p web3.NetworkEndpoints - tokens []*TokenHolders - mutex sync.RWMutex - db *db.DB - lastBlock uint64 - extProviders map[uint64]HolderProvider - coolDown time.Duration + w3p web3.NetworkEndpoints + tokens []*TokenHolders + mutex sync.RWMutex + db *db.DB + lastBlock uint64 + holderProviders map[uint64]providers.HolderProvider + coolDown time.Duration } // NewHoldersScanner function creates a new HolderScanner using the dataDir path // and the web3 endpoint URI provided. It sets up a sqlite3 database instance // and gets the number of last block scanned from it. func NewHoldersScanner(db *db.DB, w3p web3.NetworkEndpoints, - ext map[uint64]HolderProvider, coolDown time.Duration, + holderProviders map[uint64]providers.HolderProvider, coolDown time.Duration, ) (*HoldersScanner, error) { if db == nil { return nil, ErrNoDB } // create an empty scanner s := HoldersScanner{ - w3p: w3p, - tokens: []*TokenHolders{}, - db: db, - extProviders: ext, - coolDown: coolDown, + w3p: w3p, + tokens: []*TokenHolders{}, + db: db, + holderProviders: holderProviders, + coolDown: coolDown, } // get latest analyzed block ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -118,6 +119,13 @@ func (s *HoldersScanner) Start(ctx context.Context) { } } +func (s *HoldersScanner) getProvider(tokenType uint64) (providers.HolderProvider, bool) { + if provider, exists := s.holderProviders[tokenType]; exists { + return provider, true + } + return nil, false +} + // getTokensToScan function gets the information of the current tokens to scan, // including its addresses from the database. If the current database instance // does not contain any token, it returns nil addresses without error. @@ -145,28 +153,8 @@ func (s *HoldersScanner) getTokensToScan() error { } // parse last not synced token addresses for _, token := range lastNotSyncedTokens { - lastBlock := uint64(token.CreationBlock) - if lastBlock == 0 { - if networkEndpoint, ok := s.w3p.EndpointByChainID(token.ChainID); ok { - client, err := networkEndpoint.GetClient(web3.DefaultMaxWeb3ClientRetries) - if err != nil { - return err - } - web3Provider := &web3.ERC20HolderProvider{ - HexAddress: common.Bytes2Hex(token.ID), - ChainID: token.ChainID, - Client: client, - } - if err := web3Provider.Init(); err != nil { - return err - } - lastBlock, err = web3Provider.CreationBlock(ctx, nil) - if err != nil { - return err - } - } - } - if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil && blockNumber > lastBlock { + lastBlock := uint64(0) + if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil { lastBlock = blockNumber } s.tokens = append(s.tokens, new(TokenHolders).Init( @@ -202,29 +190,9 @@ func (s *HoldersScanner) getTokensToScan() error { }) // parse old not synced token addresses for _, token := range oldNotSyncedTokens { - lastBlock := uint64(token.CreationBlock) - if lastBlock == 0 { - if networkEndpoint, ok := s.w3p.EndpointByChainID(token.ChainID); ok { - client, err := networkEndpoint.GetClient(web3.DefaultMaxWeb3ClientRetries) - if err != nil { - return err - } - web3Provider := &web3.ERC20HolderProvider{ - HexAddress: common.Bytes2Hex(token.ID), - ChainID: token.ChainID, - Client: client, - } - if err := web3Provider.Init(); err != nil { - return err - } - lastBlock, err = web3Provider.CreationBlock(ctx, nil) - if err != nil { - return err - } - } - } - if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil && blockNumber > lastBlock { - lastBlock = blockNumber + lastBlock := uint64(0) + if token.LastBlock != nil { + lastBlock = uint64(token.LastBlock.(int64)) } s.tokens = append(s.tokens, new(TokenHolders).Init( common.BytesToAddress(token.ID), token.TypeID, @@ -236,28 +204,8 @@ func (s *HoldersScanner) getTokensToScan() error { return err } for _, token := range syncedTokens { - lastBlock := uint64(token.CreationBlock) - if lastBlock == 0 { - if networkEndpoint, ok := s.w3p.EndpointByChainID(token.ChainID); ok { - client, err := networkEndpoint.GetClient(web3.DefaultMaxWeb3ClientRetries) - if err != nil { - return err - } - web3Provider := &web3.ERC20HolderProvider{ - HexAddress: common.Bytes2Hex(token.ID), - ChainID: token.ChainID, - Client: client, - } - if err := web3Provider.Init(); err != nil { - return err - } - lastBlock, err = web3Provider.CreationBlock(ctx, nil) - if err != nil { - return err - } - } - } - if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil && blockNumber > lastBlock { + lastBlock := uint64(0) + if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil { lastBlock = blockNumber } s.tokens = append(s.tokens, new(TokenHolders).Init( @@ -298,6 +246,22 @@ func (s *HoldersScanner) saveHolders(th *TokenHolders) error { } else if !exists { return ErrTokenNotExists } + provider, exists := s.getProvider(th.Type()) + if !exists { + return fmt.Errorf("token type not supported") + } + if !provider.IsExternal() { + // init web3 contract state + if err := provider.SetRef(web3.Web3ProviderRef{ + HexAddress: th.Address().Hex(), + ChainID: th.ChainID, + }); err != nil { + return err + } + } + if latest, err := provider.LatestBlockNumber(ctx, []byte(th.ExternalID)); err == nil && th.LastBlock() >= latest { + th.Synced() + } _, err = qtx.UpdateTokenStatus(ctx, queries.UpdateTokenStatusParams{ Synced: th.IsSynced(), ID: th.Address().Bytes(), @@ -320,44 +284,15 @@ func (s *HoldersScanner) saveHolders(th *TokenHolders) error { // not matter if it is an external provider or a web3 one var timestamp string var rootHash []byte - if provider, isExternal := s.extProviders[th.Type()]; isExternal { - timestamp, err = provider.BlockTimestamp(ctx, th.LastBlock()) - if err != nil { - return err - } - rootHash, err = provider.BlockRootHash(ctx, th.LastBlock()) - if err != nil { - return err - } - } else { - // get correct web3 uri provider - w3Endpoint, exists := s.w3p.EndpointByChainID(th.ChainID) - if !exists { - return fmt.Errorf("chain ID not supported") - } - client, err := w3Endpoint.GetClient(web3.DefaultMaxWeb3ClientRetries) - if err != nil { - return err - } - // init web3 contract state - w3Provider := web3.ERC20HolderProvider{ - HexAddress: th.Address().Hex(), - ChainID: th.ChainID, - Client: client, - } - if err := w3Provider.Init(); err != nil { - return err - } - // get current block number timestamp and root hash, required parameters to - // create a new block in the database - timestamp, err = w3Provider.BlockTimestamp(ctx, th.LastBlock()) - if err != nil { - return err - } - rootHash, err = w3Provider.BlockRootHash(ctx, th.LastBlock()) - if err != nil { - return err - } + // get current block number timestamp and root hash, required parameters to + // create a new block in the database + timestamp, err = provider.BlockTimestamp(ctx, th.LastBlock()) + if err != nil { + return err + } + rootHash, err = provider.BlockRootHash(ctx, th.LastBlock()) + if err != nil { + return err } // if the current HoldersScanner last block not exists in the database, // create it @@ -462,6 +397,7 @@ func (s *HoldersScanner) saveHolders(th *TokenHolders) error { "chainID", th.ChainID, "externalID", th.ExternalID, "block", th.LastBlock(), + "synced", th.IsSynced(), "created", created, "updated", updated, "deleted", deleted) @@ -558,53 +494,34 @@ func (s *HoldersScanner) scanHolders(ctx context.Context, addr common.Address, c // if the token type has a external provider associated, get the holders // from it and append it to the TokenHolders struct, then save it into the // database and return - if provider, isExternal := s.extProviders[th.Type()]; isExternal { - if err := provider.SetLastBalances(ctx, []byte(th.ExternalID), th.Holders(), th.LastBlock()); err != nil { - return false, err - } - externalBalances, lastBlock, err := provider.HoldersBalances(ctx, []byte(th.ExternalID), s.lastBlock-th.LastBlock()) - if err != nil { - return false, err - } - for holder, balance := range externalBalances { - th.Append(holder, balance) - } - th.BlockDone(lastBlock) - th.Synced() - return true, s.saveHolders(th) - } - // get correct web3 uri provider - w3URI, exists := s.w3p.EndpointByChainID(th.ChainID) + provider, exists := s.getProvider(th.Type()) if !exists { - return false, fmt.Errorf("chain ID not supported") - } - client, err := w3URI.GetClient(web3.DefaultMaxWeb3ClientRetries) - if err != nil { - return false, err - } - // init web3 contract state - // TODO: switch between token types - web3Provider := &web3.ERC20HolderProvider{ - HexAddress: addr.Hex(), - ChainID: chainID, - Client: client, + return false, fmt.Errorf("token type not supported") } - if err := web3Provider.Init(); err != nil { - return th.IsSynced(), err + if !provider.IsExternal() { + if err := provider.SetRef(web3.Web3ProviderRef{ + HexAddress: th.Address().Hex(), + ChainID: th.ChainID, + }); err != nil { + return th.IsSynced(), err + } } - if err := web3Provider.SetLastBalances(ctx, nil, th.Holders(), th.LastBlock()); err != nil { + if err := provider.SetLastBalances(ctx, []byte(th.ExternalID), th.Holders(), th.LastBlock()); err != nil { return false, err } - latestBalances, lastBlock, err := web3Provider.HoldersBalances(ctx, nil, th.LastBlock()) + externalBalances, lastBlock, synced, err := provider.HoldersBalances(ctx, []byte(th.ExternalID), th.LastBlock()) if err != nil { return false, err } - for holder, balance := range latestBalances { + for holder, balance := range externalBalances { th.Append(holder, balance) } th.BlockDone(lastBlock) + if synced { + th.Synced() + } // save TokesHolders state into the database before exit of the function - return th.IsSynced(), s.saveHolders(th) + return synced, s.saveHolders(th) } // calcTokenCreationBlock function attempts to calculate the block number when @@ -628,26 +545,18 @@ func (s *HoldersScanner) calcTokenCreationBlock(ctx context.Context, index int) if err != nil { return fmt.Errorf("error getting token from database: %w", err) } - // get correct web3 uri provider - w3URI, exists := s.w3p.EndpointByChainID(tokenInfo.ChainID) - if !exists { - return fmt.Errorf("chain ID not supported") - } - // init web3 contract state - client, err := w3URI.GetClient(web3.DefaultMaxWeb3ClientRetries) - if err != nil { - return fmt.Errorf("error getting web3 client: %w", err) + provider, ok := s.getProvider(tokenInfo.TypeID) + if !ok || provider.IsExternal() { + return nil } - web3Provider := &web3.ERC20HolderProvider{ + if err := provider.SetRef(web3.Web3ProviderRef{ HexAddress: addr.Hex(), ChainID: chainID, - Client: client, - } - if err := web3Provider.Init(); err != nil { + }); err != nil { return fmt.Errorf("error intializing web3 client for this token: %w", err) } // get creation block of the current token contract - creationBlock, err := web3Provider.CreationBlock(ctx, nil) + creationBlock, err := provider.CreationBlock(ctx, nil) if err != nil { return fmt.Errorf("error getting token creation block: %w", err) } diff --git a/service/holders_provider.go b/service/providers/holders_provider.go similarity index 84% rename from service/holders_provider.go rename to service/providers/holders_provider.go index 94632fe3..5bc76711 100644 --- a/service/holders_provider.go +++ b/service/providers/holders_provider.go @@ -1,4 +1,4 @@ -package service +package providers import ( "context" @@ -15,7 +15,8 @@ type HolderProvider interface { // Init initializes the provider and its internal structures. Initial // attributes values must be defined in the struct that implements this // interface before calling this method. - Init() error + Init(conf any) error + SetRef(ref any) error // SetLastBalances sets the balances of the token holders for the given // id and from point in time and store it in a snapshot. It is used to // calculate the delta balances in the next call to HoldersBalances from @@ -23,18 +24,20 @@ type HolderProvider interface { SetLastBalances(ctx context.Context, id []byte, balances map[common.Address]*big.Int, from uint64) error // HoldersBalances returns the balances of the token holders for the given // id and delta point in time, from the stored last snapshot. - HoldersBalances(ctx context.Context, id []byte, to uint64) (map[common.Address]*big.Int, uint64, error) + HoldersBalances(ctx context.Context, id []byte, to uint64) (map[common.Address]*big.Int, uint64, bool, error) // Close closes the provider and its internal structures. Close() error + IsExternal() bool // Token realated methods Address() common.Address Type() uint64 - NetworkID() uint64 + ChainID() uint64 Name(id []byte) (string, error) Symbol(id []byte) (string, error) Decimals(id []byte) (uint64, error) TotalSupply(id []byte) (*big.Int, error) - BalanceOf(id []byte, addr common.Address) (*big.Int, error) + BalanceOf(addr common.Address, id []byte) (*big.Int, error) + BalanceAt(ctx context.Context, addr common.Address, id []byte, blockNumber uint64) (*big.Int, error) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) LatestBlockNumber(ctx context.Context, id []byte) (uint64, error) diff --git a/service/poap/poap_provider.go b/service/providers/poap/poap_provider.go similarity index 92% rename from service/poap/poap_provider.go rename to service/providers/poap/poap_provider.go index bfb29d89..bf262fa9 100644 --- a/service/poap/poap_provider.go +++ b/service/providers/poap/poap_provider.go @@ -11,7 +11,7 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" - "github.com/vocdoni/census3/service/web3" + "github.com/vocdoni/census3/service/providers" "go.vocdoni.io/dvote/log" ) @@ -28,7 +28,6 @@ const ( POAP_URI = "/event/%s/poaps" // POAP_CONTRACT_ADDRESS is the address of the POAP contract. POAP_CONTRACT_ADDRESS = "0x22c1f6050e56d2876009903609a2cc3fef83b415" - POAP_CONTRACT_TYPE = web3.CONTRACT_TYPE_POAP ) // EventAPIResponse is the struct that stores the response of the POAP API @@ -68,21 +67,38 @@ type POAPHolderProvider struct { snapshotsMtx *sync.RWMutex } +type POAPConfig struct { + URI string + AccessToken string +} + // Init initializes the POAP external provider with the database provided. // It returns an error if the POAP access token or api endpoint uri is not // defined. -func (p *POAPHolderProvider) Init() error { - if p.URI == "" { +func (p *POAPHolderProvider) Init(iconf any) error { + // parse config + conf, ok := iconf.(POAPConfig) + if !ok { + return fmt.Errorf("bad config type, it must be a POAPConfig struct") + } + + if conf.URI == "" { return fmt.Errorf("no POAP URI defined") } - if p.AccessToken == "" { + if conf.AccessToken == "" { return fmt.Errorf("no POAP access token defined") } + p.URI = conf.URI + p.AccessToken = conf.AccessToken p.snapshots = make(map[string]*POAPSnapshot) p.snapshotsMtx = &sync.RWMutex{} return nil } +func (p *POAPHolderProvider) SetRef(_ any) error { + return nil +} + // SetLastBalances sets the balances of the token holders for the given id and // from point in time and store it in a snapshot. func (p *POAPHolderProvider) SetLastBalances(_ context.Context, id []byte, @@ -101,13 +117,15 @@ func (p *POAPHolderProvider) SetLastBalances(_ context.Context, id []byte, // and delta point in time. It requests the list of token holders to the POAP // API parsing every POAP holder for the event ID provided and calculate the // balances of the token holders from the last snapshot. -func (p *POAPHolderProvider) HoldersBalances(_ context.Context, id []byte, delta uint64) (map[common.Address]*big.Int, uint64, error) { +func (p *POAPHolderProvider) HoldersBalances(_ context.Context, id []byte, delta uint64) ( + map[common.Address]*big.Int, uint64, bool, error, +) { // parse eventID from id eventID := string(id) // get last snapshot newSnapshot, err := p.lastHolders(eventID) if err != nil { - return nil, 0, err + return nil, 0, false, err } // calculate snapshot from from := delta @@ -124,7 +142,7 @@ func (p *POAPHolderProvider) HoldersBalances(_ context.Context, id []byte, delta snapshot: newSnapshot, } // return partials from last snapshot - return partialBalances, from, nil + return partialBalances, from, true, nil } // Close method is not implemented in the POAP external provider. By default it @@ -133,15 +151,19 @@ func (p *POAPHolderProvider) Close() error { return nil } +func (p *POAPHolderProvider) IsExternal() bool { + return true +} + func (p *POAPHolderProvider) Address() common.Address { return common.HexToAddress(POAP_CONTRACT_ADDRESS) } func (p *POAPHolderProvider) Type() uint64 { - return POAP_CONTRACT_TYPE + return providers.CONTRACT_TYPE_POAP } -func (p *POAPHolderProvider) NetworkID() uint64 { +func (p *POAPHolderProvider) ChainID() uint64 { return 1 } @@ -173,7 +195,7 @@ func (p *POAPHolderProvider) TotalSupply(_ []byte) (*big.Int, error) { return big.NewInt(0), nil } -func (p *POAPHolderProvider) BalanceOf(id []byte, addr common.Address) (*big.Int, error) { +func (p *POAPHolderProvider) BalanceOf(addr common.Address, id []byte) (*big.Int, error) { // parse eventID from id eventID := string(id) // get the last stored snapshot @@ -188,6 +210,10 @@ func (p *POAPHolderProvider) BalanceOf(id []byte, addr common.Address) (*big.Int return nil, fmt.Errorf("no snapshot found for eventID %s", eventID) } +func (p *POAPHolderProvider) BalanceAt(_ context.Context, _ common.Address, _ []byte, _ uint64) (*big.Int, error) { + return big.NewInt(0), fmt.Errorf("not implemented") +} + // BlockTimestamp method is not implemented in the POAP external provider. By // default it returns an empty string and nil error. func (p *POAPHolderProvider) BlockTimestamp(_ context.Context, _ uint64) (string, error) { diff --git a/service/poap/poap_provider_test.go b/service/providers/poap/poap_provider_test.go similarity index 100% rename from service/poap/poap_provider_test.go rename to service/providers/poap/poap_provider_test.go diff --git a/service/providers/types.go b/service/providers/types.go new file mode 100644 index 00000000..3dd6b82e --- /dev/null +++ b/service/providers/types.go @@ -0,0 +1,38 @@ +package providers + +const ( + // CONTRACT TYPES + CONTRACT_TYPE_UNKNOWN uint64 = iota + CONTRACT_TYPE_ERC20 + CONTRACT_TYPE_ERC721 + CONTRACT_TYPE_ERC1155 + CONTRACT_TYPE_ERC777 + CONTRACT_TYPE_CUSTOM_NATION3_VENATION + CONTRACT_TYPE_CUSTOM_ARAGON_WANT + CONTRACT_TYPE_ERC721_BURNED + CONTRACT_TYPE_POAP +) + +var TokenTypeStringMap = map[uint64]string{ + CONTRACT_TYPE_UNKNOWN: "unknown", + CONTRACT_TYPE_ERC20: "erc20", + CONTRACT_TYPE_ERC721_BURNED: "erc721burned", + CONTRACT_TYPE_ERC1155: "erc1155", + CONTRACT_TYPE_ERC777: "erc777", + CONTRACT_TYPE_CUSTOM_NATION3_VENATION: "nation3", + CONTRACT_TYPE_CUSTOM_ARAGON_WANT: "want", + CONTRACT_TYPE_ERC721: "erc721", + CONTRACT_TYPE_POAP: "poap", +} + +var TokenTypeIntMap = map[string]uint64{ + "unknown": CONTRACT_TYPE_UNKNOWN, + "erc20": CONTRACT_TYPE_ERC20, + "erc721": CONTRACT_TYPE_ERC721, + "erc1155": CONTRACT_TYPE_ERC1155, + "erc777": CONTRACT_TYPE_ERC777, + "nation3": CONTRACT_TYPE_CUSTOM_NATION3_VENATION, + "want": CONTRACT_TYPE_CUSTOM_ARAGON_WANT, + "erc721burned": CONTRACT_TYPE_ERC721_BURNED, + "poap": CONTRACT_TYPE_POAP, +} diff --git a/state/const.go b/service/providers/web3/const.go similarity index 67% rename from state/const.go rename to service/providers/web3/const.go index 5b830aa7..2f3b5d03 100644 --- a/state/const.go +++ b/service/providers/web3/const.go @@ -1,6 +1,22 @@ -package state +package web3 -const timeLayout = "2006-01-02T15:04:05Z07:00" +import "time" + +const ( + DefaultMaxWeb3ClientRetries = 3 +) +const ( + shortNameSourceUri = "https://chainid.network/chains_mini.json" + checkNetworkEndpointsTimeout = time.Second * 10 + timeLayout = "2006-01-02T15:04:05Z07:00" +) + +var DefaultNetworkEndpoint = &NetworkEndpoint{ + ChainID: 5, + Name: "Goerli", + ShortName: "gor", + URIs: []string{"https://eth-goerli.api.onfinality.io/public"}, +} const ( // OTHER CONSTANTS @@ -21,23 +37,4 @@ const ( LOG_TOPIC_WANT_DEPOSIT = "e1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c" LOG_TOPIC_WANT_WITHDRAWAL = "7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65" // Add more topics here -) - -const ( - // CONTRACT TYPES - CONTRACT_TYPE_UNKNOWN TokenType = iota - CONTRACT_TYPE_ERC20 - CONTRACT_TYPE_ERC721 - CONTRACT_TYPE_ERC1155 - CONTRACT_TYPE_ERC777 - CONTRACT_TYPE_CUSTOM_NATION3_VENATION - CONTRACT_TYPE_CUSTOM_ARAGON_WANT - CONTRACT_TYPE_ERC721_BURNED - CONTRACT_TYPE_POAP -) - -const ( - // POAP SPECIFIC CONSTANTS - CONTRACT_POAP_ADDRESS = "0x22c1f6050e56d2876009903609a2cc3fef83b415" - CONTRACT_POAP_SYMBOL = "POAP" // the POAP contract has 'The Proof of Attendance Protocol' as a symbol -) +) \ No newline at end of file diff --git a/service/web3/endpoint.go b/service/providers/web3/endpoint.go similarity index 100% rename from service/web3/endpoint.go rename to service/providers/web3/endpoint.go diff --git a/service/web3/endpoint_test.go b/service/providers/web3/endpoint_test.go similarity index 100% rename from service/web3/endpoint_test.go rename to service/providers/web3/endpoint_test.go diff --git a/service/providers/web3/erc20_provider.go b/service/providers/web3/erc20_provider.go new file mode 100644 index 00000000..fe3e68fd --- /dev/null +++ b/service/providers/web3/erc20_provider.go @@ -0,0 +1,309 @@ +package web3 + +import ( + "context" + "errors" + "fmt" + "math/big" + "strings" + "sync" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + erc20 "github.com/vocdoni/census3/contracts/erc/erc20" + "github.com/vocdoni/census3/service/providers" + "go.vocdoni.io/dvote/log" +) + +type ERC20HolderProvider struct { + endpoints NetworkEndpoints + client *ethclient.Client + + contract *erc20.ERC20Contract + address common.Address + chainID uint64 + name string + symbol string + decimals uint64 + totalSupply *big.Int + creationBlock uint64 + + balances map[common.Address]*big.Int + balancesMtx sync.RWMutex + balancesBlock uint64 +} + +func (p *ERC20HolderProvider) Init(iconf any) error { + // parse the config and set the endpoints + conf, ok := iconf.(Web3ProviderConfig) + if !ok { + return errors.New("invalid config type, it must be Web3ProviderConfig") + } + p.endpoints = conf.Endpoints + // reset the internal balances + p.balances = make(map[common.Address]*big.Int) + p.balancesMtx = sync.RWMutex{} + // set the reference if the address and chainID are defined in the config + if conf.HexAddress != "" && conf.ChainID > 0 { + return p.SetRef(Web3ProviderRef{ + HexAddress: conf.HexAddress, + ChainID: conf.ChainID, + }) + } + return nil +} + +func (p *ERC20HolderProvider) SetRef(iref any) error { + if p.endpoints == nil { + return errors.New("endpoints not defined") + } + ref, ok := iref.(Web3ProviderRef) + if !ok { + return errors.New("invalid ref type, it must be Web3ProviderRef") + } + currentEndpoint, exists := p.endpoints.EndpointByChainID(ref.ChainID) + if !exists { + return errors.New("endpoint not found for the given chainID") + } + // connect to the endpoint + client, err := currentEndpoint.GetClient(DefaultMaxWeb3ClientRetries) + if err != nil { + return errors.Join(ErrConnectingToWeb3Client, fmt.Errorf("[ERC20] %s: %w", ref.HexAddress, err)) + } + // parse the address and initialize the contract + address := common.HexToAddress(ref.HexAddress) + if p.contract, err = erc20.NewERC20Contract(address, client); err != nil { + return errors.Join(ErrInitializingContract, fmt.Errorf("[ERC20] %s: %w", p.address, err)) + } + // reset the internal attributes + p.client = client + p.address = address + p.chainID = ref.ChainID + // reset balances + p.balancesMtx.Lock() + defer p.balancesMtx.Unlock() + p.balances = make(map[common.Address]*big.Int) + return nil +} + +func (p *ERC20HolderProvider) SetLastBalances(ctx context.Context, id []byte, balances map[common.Address]*big.Int, from uint64) error { + p.balancesMtx.Lock() + defer p.balancesMtx.Unlock() + + if from < p.balancesBlock { + return errors.New("from block is lower than the last block analyzed") + } + p.balancesBlock = from + p.balances = balances + return nil +} + +func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fromBlock uint64) ( + map[common.Address]*big.Int, uint64, bool, error, +) { + // calculate the range of blocks to scan, by default take the last block + // scanned and scan to the latest block + toBlock, err := p.LatestBlockNumber(ctx, nil) + if err != nil { + return nil, fromBlock, false, err + } + // if the range is too big, scan only a part of it using the constant + // BLOCKS_TO_SCAN_AT_ONCE + if toBlock-fromBlock > BLOCKS_TO_SCAN_AT_ONCE { + toBlock = fromBlock + MAX_SCAN_BLOCKS_PER_ITERATION + } + logCount := 0 + blocksRange := BLOCKS_TO_SCAN_AT_ONCE + log.Infow("scan iteration", + "address", p.address, + "type", providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC20], + "from", fromBlock, + "to", toBlock) + // some variables to calculate the progress + startTime := time.Now() + initialBlock := fromBlock + lastBlock := fromBlock + p.balancesMtx.RLock() + initialHolders := len(p.balances) + p.balancesMtx.RUnlock() + // iterate scanning the logs in the range of blocks until the last block + // is reached + for fromBlock < toBlock { + select { + case <-ctx.Done(): + log.Warnf("scan graceful canceled by context") + return p.balances, lastBlock, false, nil + default: + if logCount > MAX_SCAN_LOGS_PER_ITERATION { + return p.balances, lastBlock, false, nil + } + // compose the filter to get the logs of the ERC20 Transfer events + filter := ethereum.FilterQuery{ + Addresses: []common.Address{p.address}, + FromBlock: new(big.Int).SetUint64(fromBlock), + ToBlock: new(big.Int).SetUint64(fromBlock + blocksRange), + Topics: [][]common.Hash{ + {common.HexToHash(LOG_TOPIC_ERC20_TRANSFER)}, + }, + } + // get the logs and check if there are any errors + logs, err := p.client.FilterLogs(ctx, filter) + if err != nil { + // if the error is about the query returning more than the maximum + // allowed logs, split the range of blocks in half and try again + if strings.Contains(err.Error(), "query returned more than") { + blocksRange /= 2 + log.Warnf("too much results on query, decreasing blocks to %d", blocksRange) + continue + } + return nil, lastBlock, false, errors.Join(ErrScanningTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.address, err)) + } + // if there are no logs, the range of blocks is empty, so return the + // balances + if len(logs) == 0 { + fromBlock += blocksRange + continue + } + logCount += len(logs) + // iterate the logs and update the balances + for _, log := range logs { + logData, err := p.contract.ERC20ContractFilterer.ParseTransfer(log) + if err != nil { + return nil, lastBlock, false, errors.Join(ErrParsingTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.address, err)) + } + // update balances + p.balancesMtx.Lock() + if toBalance, ok := p.balances[logData.To]; ok { + p.balances[logData.To] = new(big.Int).Add(toBalance, logData.Value) + } else { + p.balances[logData.To] = logData.Value + } + if fromBalance, ok := p.balances[logData.From]; ok { + p.balances[logData.From] = new(big.Int).Sub(fromBalance, logData.Value) + } else { + p.balances[logData.From] = new(big.Int).Neg(logData.Value) + } + p.balancesMtx.Unlock() + lastBlock = log.BlockNumber + } + // update the fromBlock to the last block scanned + fromBlock += blocksRange + } + } + p.balancesMtx.RLock() + finalHolders := len(p.balances) + p.balancesMtx.RUnlock() + log.Infow("saving blocks", + "count", finalHolders-initialHolders, + "logs", logCount, + "blocks/s", 1000*float32(fromBlock-initialBlock)/float32(time.Since(startTime).Milliseconds()), + "took", time.Since(startTime).Seconds(), + "progress", fmt.Sprintf("%d%%", (fromBlock*100)/toBlock)) + return p.balances, lastBlock, true, nil +} + +func (p *ERC20HolderProvider) Close() error { + return nil +} + +func (p *ERC20HolderProvider) IsExternal() bool { + return false +} + +func (p *ERC20HolderProvider) Address() common.Address { + return p.address +} + +func (p *ERC20HolderProvider) Type() uint64 { + return providers.CONTRACT_TYPE_ERC20 +} + +func (p *ERC20HolderProvider) ChainID() uint64 { + return p.chainID +} + +func (p *ERC20HolderProvider) Name(_ []byte) (string, error) { + var err error + if p.name == "" { + p.name, err = p.contract.ERC20ContractCaller.Name(nil) + } + return p.name, err +} + +func (p *ERC20HolderProvider) Symbol(_ []byte) (string, error) { + var err error + if p.symbol == "" { + p.symbol, err = p.contract.ERC20ContractCaller.Symbol(nil) + } + return p.symbol, err +} + +func (p *ERC20HolderProvider) Decimals(_ []byte) (uint64, error) { + if p.decimals == 0 { + decimals, err := p.contract.ERC20ContractCaller.Decimals(nil) + if err != nil { + return 0, err + } + p.decimals = uint64(decimals) + } + return p.decimals, nil +} + +func (p *ERC20HolderProvider) TotalSupply(_ []byte) (*big.Int, error) { + var err error + if p.totalSupply == nil { + p.totalSupply, err = p.contract.ERC20ContractCaller.TotalSupply(nil) + } + return p.totalSupply, err +} + +func (p *ERC20HolderProvider) BalanceOf(addr common.Address, _ []byte) (*big.Int, error) { + return p.contract.ERC20ContractCaller.BalanceOf(nil, addr) +} + +func (p *ERC20HolderProvider) BalanceAt(ctx context.Context, addr common.Address, _ []byte, blockNumber uint64) (*big.Int, error) { + return p.client.BalanceAt(ctx, addr, new(big.Int).SetUint64(blockNumber)) +} + +func (p *ERC20HolderProvider) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) { + blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetUint64(blockNumber)) + if err != nil { + return "", err + } + return time.Unix(int64(blockHeader.Time), 0).Format(timeLayout), nil +} + +func (p *ERC20HolderProvider) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) { + blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) + if err != nil { + return nil, err + } + return blockHeader.Root.Bytes(), nil +} + +func (p *ERC20HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) (uint64, error) { + lastBlockHeader, err := p.client.HeaderByNumber(ctx, nil) + if err != nil { + return 0, err + } + return lastBlockHeader.Number.Uint64(), nil +} + +func (p *ERC20HolderProvider) CreationBlock(ctx context.Context, _ []byte) (uint64, error) { + var err error + if p.creationBlock == 0 { + var lastBlock uint64 + lastBlock, err = p.LatestBlockNumber(ctx, nil) + if err != nil { + return 0, err + } + p.creationBlock, err = creationBlockInRange(p.client, ctx, p.address, 0, lastBlock) + } + return p.creationBlock, err +} + +func (p *ERC20HolderProvider) IconURI(_ []byte) (string, error) { + return "", nil +} diff --git a/service/providers/web3/errors.go b/service/providers/web3/errors.go new file mode 100644 index 00000000..c265823d --- /dev/null +++ b/service/providers/web3/errors.go @@ -0,0 +1,11 @@ +package web3 + +import "fmt" + +var ( + ErrClientNotSet = fmt.Errorf("client not set") + ErrConnectingToWeb3Client = fmt.Errorf("client not set") + ErrInitializingContract = fmt.Errorf("error initializing token contract") + ErrScanningTokenLogs = fmt.Errorf("error scanning token logs") + ErrParsingTokenLogs = fmt.Errorf("error parsing token logs") +) diff --git a/service/web3/helpers.go b/service/providers/web3/helpers.go similarity index 92% rename from service/web3/helpers.go rename to service/providers/web3/helpers.go index bb24d2ee..10f829bb 100644 --- a/service/web3/helpers.go +++ b/service/providers/web3/helpers.go @@ -8,13 +8,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" + "github.com/vocdoni/census3/service/providers" ) func TokenTypeFromString(s string) uint64 { - if c, ok := TokenTypeIntMap[s]; ok { + if c, ok := providers.TokenTypeIntMap[s]; ok { return c } - return CONTRACT_TYPE_UNKNOWN + return providers.CONTRACT_TYPE_UNKNOWN } // creationBlockInRange function finds the block number of a contract between diff --git a/service/providers/web3/web3_provider.go b/service/providers/web3/web3_provider.go new file mode 100644 index 00000000..a7a51c20 --- /dev/null +++ b/service/providers/web3/web3_provider.go @@ -0,0 +1,11 @@ +package web3 + +type Web3ProviderRef struct { + HexAddress string + ChainID uint64 +} + +type Web3ProviderConfig struct { + Web3ProviderRef + Endpoints NetworkEndpoints +} diff --git a/service/tokenholders_test.go b/service/tokenholders_test.go index d0dbb41f..64ce8f2b 100644 --- a/service/tokenholders_test.go +++ b/service/tokenholders_test.go @@ -6,30 +6,30 @@ import ( "github.com/ethereum/go-ethereum/common" qt "github.com/frankban/quicktest" - "github.com/vocdoni/census3/service/web3" + "github.com/vocdoni/census3/service/providers" ) func TestTokenHoldersInit(t *testing.T) { c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 0, "") + th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 0, "") c.Assert(th.address.String(), qt.Equals, MonkeysAddress.String()) - c.Assert(th.ctype, qt.Equals, web3.CONTRACT_TYPE_ERC20) + c.Assert(th.ctype, qt.Equals, providers.CONTRACT_TYPE_ERC20) c.Assert(th.lastBlock.Load(), qt.Equals, MonkeysCreationBlock) c.Assert(th.synced.Load(), qt.IsFalse) } func TestHolders(t *testing.T) { c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") c.Assert(th.address.String(), qt.Equals, MonkeysAddress.String()) - c.Assert(th.ctype, qt.Equals, web3.CONTRACT_TYPE_ERC20) + c.Assert(th.ctype, qt.Equals, providers.CONTRACT_TYPE_ERC20) c.Assert(th.lastBlock.Load(), qt.Equals, MonkeysCreationBlock) c.Assert(th.synced.Load(), qt.IsFalse) } func TestAppend(t *testing.T) { c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") holderBalance := new(big.Int).SetUint64(16000000000000000000) @@ -43,7 +43,7 @@ func TestAppend(t *testing.T) { func TestExists(t *testing.T) { c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") holderBalance := new(big.Int).SetUint64(16000000000000000000) @@ -54,7 +54,7 @@ func TestExists(t *testing.T) { func TestDel(t *testing.T) { c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") holderBalance := new(big.Int).SetUint64(16000000000000000000) @@ -71,7 +71,7 @@ func TestDel(t *testing.T) { func TestFlushHolders(t *testing.T) { c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") holderBalance := new(big.Int).SetUint64(16000000000000000000) @@ -87,7 +87,7 @@ func TestFlushHolders(t *testing.T) { func TestBlockDone(t *testing.T) { c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") _, exists := th.blocks.Load(MonkeysCreationBlock + 500) c.Assert(exists, qt.IsFalse) @@ -100,7 +100,7 @@ func TestBlockDone(t *testing.T) { func TestHasBlock(t *testing.T) { c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") c.Assert(th.HasBlock(MonkeysCreationBlock), qt.IsFalse) th.BlockDone(MonkeysCreationBlock) @@ -109,7 +109,7 @@ func TestHasBlock(t *testing.T) { func TestLastBlock(t *testing.T) { c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") c.Assert(th.LastBlock(), qt.Equals, MonkeysCreationBlock) th.BlockDone(MonkeysCreationBlock + 1) @@ -120,7 +120,7 @@ func TestLastBlock(t *testing.T) { func TestSynced(t *testing.T) { c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") c.Assert(th.synced.Load(), qt.IsFalse) th.Synced() @@ -129,7 +129,7 @@ func TestSynced(t *testing.T) { func TestIsSynced(t *testing.T) { c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, web3.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") + th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") c.Assert(th.IsSynced(), qt.IsFalse) th.Synced() diff --git a/service/web3/const.go b/service/web3/const.go deleted file mode 100644 index a72fa605..00000000 --- a/service/web3/const.go +++ /dev/null @@ -1,77 +0,0 @@ -package web3 - -import "time" - -const ( - DefaultMaxWeb3ClientRetries = 3 -) -const ( - shortNameSourceUri = "https://chainid.network/chains_mini.json" - checkNetworkEndpointsTimeout = time.Second * 10 - timeLayout = "2006-01-02T15:04:05Z07:00" -) - -var DefaultNetworkEndpoint = &NetworkEndpoint{ - ChainID: 5, - Name: "Goerli", - ShortName: "gor", - URIs: []string{"https://eth-goerli.api.onfinality.io/public"}, -} - -const ( - // OTHER CONSTANTS - MAX_SCAN_BLOCKS_PER_ITERATION = 1000000 - MAX_SCAN_LOGS_PER_ITERATION = 100000 - MAX_NEW_HOLDER_CANDIDATES_PER_ITERATION = 5000 - BLOCKS_TO_SCAN_AT_ONCE = uint64(20000) - NULL_ADDRESS = "0" -) - -const ( - // EVM LOG TOPICS - LOG_TOPIC_VENATION_DEPOSIT = "4566dfc29f6f11d13a418c26a02bef7c28bae749d4de47e4e6a7cddea6730d59" - LOG_TOPIC_VENATION_WITHDRAW = "f279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568" - LOG_TOPIC_ERC20_TRANSFER = "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" - LOG_TOPIC_ERC1155_TRANSFER_SINGLE = "c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62" - LOG_TOPIC_ERC1155_TRANSFER_BATCH = "4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb" - LOG_TOPIC_WANT_DEPOSIT = "e1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c" - LOG_TOPIC_WANT_WITHDRAWAL = "7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65" - // Add more topics here -) - -const ( - // CONTRACT TYPES - CONTRACT_TYPE_UNKNOWN uint64 = iota - CONTRACT_TYPE_ERC20 - CONTRACT_TYPE_ERC721 - CONTRACT_TYPE_ERC1155 - CONTRACT_TYPE_ERC777 - CONTRACT_TYPE_CUSTOM_NATION3_VENATION - CONTRACT_TYPE_CUSTOM_ARAGON_WANT - CONTRACT_TYPE_ERC721_BURNED - CONTRACT_TYPE_POAP -) - -var TokenTypeStringMap = map[uint64]string{ - CONTRACT_TYPE_UNKNOWN: "unknown", - CONTRACT_TYPE_ERC20: "erc20", - CONTRACT_TYPE_ERC721_BURNED: "erc721burned", - CONTRACT_TYPE_ERC1155: "erc1155", - CONTRACT_TYPE_ERC777: "erc777", - CONTRACT_TYPE_CUSTOM_NATION3_VENATION: "nation3", - CONTRACT_TYPE_CUSTOM_ARAGON_WANT: "want", - CONTRACT_TYPE_ERC721: "erc721", - CONTRACT_TYPE_POAP: "poap", -} - -var TokenTypeIntMap = map[string]uint64{ - "unknown": CONTRACT_TYPE_UNKNOWN, - "erc20": CONTRACT_TYPE_ERC20, - "erc721": CONTRACT_TYPE_ERC721, - "erc1155": CONTRACT_TYPE_ERC1155, - "erc777": CONTRACT_TYPE_ERC777, - "nation3": CONTRACT_TYPE_CUSTOM_NATION3_VENATION, - "want": CONTRACT_TYPE_CUSTOM_ARAGON_WANT, - "erc721burned": CONTRACT_TYPE_ERC721_BURNED, - "poap": CONTRACT_TYPE_POAP, -} diff --git a/service/web3/erc20_provider.go b/service/web3/erc20_provider.go deleted file mode 100644 index bd53e43e..00000000 --- a/service/web3/erc20_provider.go +++ /dev/null @@ -1,232 +0,0 @@ -package web3 - -import ( - "context" - "errors" - "fmt" - "math/big" - "strings" - "sync" - "time" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" - erc20 "github.com/vocdoni/census3/contracts/erc/erc20" - "go.vocdoni.io/dvote/log" -) - -type ERC20HolderProvider struct { - HexAddress string - ChainID uint64 - Client *ethclient.Client - - contract *erc20.ERC20Contract - address common.Address - name string - symbol string - decimals uint64 - totalSupply *big.Int - creationBlock uint64 - - balances map[common.Address]*big.Int - balancesMtx sync.RWMutex - balancesBlock uint64 -} - -func (p *ERC20HolderProvider) Init() error { - if p.HexAddress == "" || p.ChainID == 0 || p.Client == nil { - return ErrInvalidProviderAttributes - } - p.address = common.HexToAddress(p.HexAddress) - var err error - p.contract, err = erc20.NewERC20Contract(p.address, p.Client) - if err != nil { - return errors.Join(ErrInitializingContract, fmt.Errorf("[ERC20] %s: %w", p.HexAddress, err)) - } - p.balancesBlock, err = p.CreationBlock(context.Background(), nil) - p.balances = make(map[common.Address]*big.Int) - p.balancesMtx = sync.RWMutex{} - return err -} - -func (p *ERC20HolderProvider) SetLastBalances(ctx context.Context, id []byte, balances map[common.Address]*big.Int, from uint64) error { - p.balancesMtx.Lock() - defer p.balancesMtx.Unlock() - - if from < p.balancesBlock { - return errors.New("from block is lower than the last block analyzed") - } - p.balancesBlock = from - p.balances = balances - return nil -} - -func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fromBlock uint64) (map[common.Address]*big.Int, uint64, error) { - // calculate the range of blocks to scan, by default take the last block - // scanned and scan to the latest block - toBlock, err := p.LatestBlockNumber(ctx, nil) - if err != nil { - return nil, fromBlock, err - } - // if the range is too big, scan only a part of it using the constant - // BLOCKS_TO_SCAN_AT_ONCE - if toBlock > fromBlock+BLOCKS_TO_SCAN_AT_ONCE { - toBlock = fromBlock + BLOCKS_TO_SCAN_AT_ONCE - } - log.Infow("scanning ERC20 logs", - "fromBlock", fromBlock, - "toBlock", toBlock, - "address", p.address.Hex()) - // iterate scanning the logs in the range of blocks until the last block - // is reached - totalLogs := 0 - for fromBlock < toBlock { - if totalLogs > MAX_SCAN_LOGS_PER_ITERATION { - return p.balances, toBlock, nil - } - // compose the filter to get the logs of the ERC20 Transfer events - filter := ethereum.FilterQuery{ - Addresses: []common.Address{p.address}, - FromBlock: new(big.Int).SetUint64(fromBlock), - ToBlock: new(big.Int).SetUint64(toBlock), - Topics: [][]common.Hash{ - {common.HexToHash(LOG_TOPIC_ERC20_TRANSFER)}, - }, - } - // get the logs and check if there are any errors - logs, err := p.Client.FilterLogs(ctx, filter) - if err != nil { - // if the error is about the query returning more than the maximum - // allowed logs, split the range of blocks in half and try again - if strings.Contains(err.Error(), "query returned more than") { - toBlock = fromBlock + ((toBlock - fromBlock) / 2) - continue - } - return nil, fromBlock, errors.Join(ErrScanningTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.HexAddress, err)) - } - // if there are no logs, the range of blocks is empty, so return the - // balances - if len(logs) == 0 { - return p.balances, toBlock, nil - } - totalLogs += len(logs) - // iterate the logs and update the balances - for _, log := range logs { - logData, err := p.contract.ERC20ContractFilterer.ParseTransfer(log) - if err != nil { - return nil, log.BlockNumber, errors.Join(ErrParsingTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.HexAddress, err)) - } - // update balances - p.balancesMtx.Lock() - if toBalance, ok := p.balances[logData.To]; ok { - p.balances[logData.To] = new(big.Int).Add(toBalance, logData.Value) - } else { - p.balances[logData.To] = logData.Value - } - if fromBalance, ok := p.balances[logData.From]; ok { - p.balances[logData.From] = new(big.Int).Sub(fromBalance, logData.Value) - } else { - p.balances[logData.From] = new(big.Int).Neg(logData.Value) - } - p.balancesMtx.Unlock() - } - } - return p.balances, toBlock, nil -} - -func (p *ERC20HolderProvider) Close() error { - return nil -} - -func (p *ERC20HolderProvider) Address() common.Address { - return p.address -} - -func (p *ERC20HolderProvider) Type() uint64 { - return CONTRACT_TYPE_ERC20 -} - -func (p *ERC20HolderProvider) NetworkID() uint64 { - return p.ChainID -} - -func (p *ERC20HolderProvider) Name(_ []byte) (string, error) { - var err error - if p.name == "" { - p.name, err = p.contract.ERC20ContractCaller.Name(nil) - } - return p.name, err -} - -func (p *ERC20HolderProvider) Symbol(_ []byte) (string, error) { - var err error - if p.symbol == "" { - p.symbol, err = p.contract.ERC20ContractCaller.Symbol(nil) - } - return p.symbol, err -} - -func (p *ERC20HolderProvider) Decimals(_ []byte) (uint64, error) { - if p.decimals == 0 { - decimals, err := p.contract.ERC20ContractCaller.Decimals(nil) - if err != nil { - return 0, err - } - p.decimals = uint64(decimals) - } - return p.decimals, nil -} - -func (p *ERC20HolderProvider) TotalSupply(_ []byte) (*big.Int, error) { - var err error - if p.totalSupply == nil { - p.totalSupply, err = p.contract.ERC20ContractCaller.TotalSupply(nil) - } - return p.totalSupply, err -} - -func (p *ERC20HolderProvider) BalanceOf(_ []byte, addr common.Address) (*big.Int, error) { - return p.contract.ERC20ContractCaller.BalanceOf(nil, addr) -} - -func (p *ERC20HolderProvider) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) { - blockHeader, err := p.Client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) - if err != nil { - return "", err - } - return time.Unix(int64(blockHeader.Time), 0).Format(timeLayout), nil -} - -func (p *ERC20HolderProvider) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) { - blockHeader, err := p.Client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) - if err != nil { - return nil, err - } - return blockHeader.Root.Bytes(), nil -} - -func (p *ERC20HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) (uint64, error) { - lastBlockHeader, err := p.Client.HeaderByNumber(ctx, nil) - if err != nil { - return 0, err - } - return lastBlockHeader.Number.Uint64(), nil -} - -func (p *ERC20HolderProvider) CreationBlock(ctx context.Context, _ []byte) (uint64, error) { - var err error - if p.creationBlock == 0 { - var lastBlock uint64 - lastBlock, err = p.LatestBlockNumber(ctx, nil) - if err != nil { - return 0, err - } - p.creationBlock, err = creationBlockInRange(p.Client, ctx, p.address, 0, lastBlock) - } - return p.creationBlock, err -} - -func (p *ERC20HolderProvider) IconURI(_ []byte) (string, error) { - return "", nil -} diff --git a/service/web3/errors.go b/service/web3/errors.go deleted file mode 100644 index 8e27e0b1..00000000 --- a/service/web3/errors.go +++ /dev/null @@ -1,10 +0,0 @@ -package web3 - -import "fmt" - -var ( - ErrInvalidProviderAttributes = fmt.Errorf("invalid provider attributes") - ErrInitializingContract = fmt.Errorf("error initializing token contract") - ErrScanningTokenLogs = fmt.Errorf("error scanning token logs") - ErrParsingTokenLogs = fmt.Errorf("error parsing token logs") -) diff --git a/state/README.md b/state/README.md deleted file mode 100644 index 4a19043b..00000000 --- a/state/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Contract State - -This directory contains all the logic for fetching token information and token holders from an Ethereum contract. - -- `const.go`: General constants used in the package. Also contains the list of supported tokens. If you want to support a new token, add it here. -- `state.go`: Contains the `State` struct, which is the main struct for storing token information and token holders. -- `web3.go`: Contains the `Web3` struct, which is the main struct for interacting with the Ethereum blockchain via the defined methods. If you want to add a new token that requires a different way of fetching the token holders, add the custom logic here. diff --git a/state/helper_test.go b/state/helper_test.go deleted file mode 100644 index 301f3e54..00000000 --- a/state/helper_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package state - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" -) - -var ( - MonkeysAddress = common.HexToAddress("0xF530280176385AF31177D78BbFD5eA3f6D07488A") - MonkeysCreationBlock = uint64(8901659) - MonkeysSymbol = "MON" - MonkeysName = "Monkeys" - MonkeysDecimals = int64(18) - MonkeysTotalSupply, _ = new(big.Int).SetString("82000000000000000000", 10) - MonkeysHolders = map[common.Address]*big.Int{ - common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012"): new(big.Int).SetUint64(16000000000000000000), - common.HexToAddress("0x38d2BC91B89928f78cBaB3e4b1949e28787eC7a3"): new(big.Int).SetUint64(13000000000000000000), - common.HexToAddress("0xF752B527E2ABA395D1Ba4C0dE9C147B763dDA1f4"): new(big.Int).SetUint64(12000000000000000000), - common.HexToAddress("0xe1308a8d0291849bfFb200Be582cB6347FBE90D9"): new(big.Int).SetUint64(9000000000000000000), - common.HexToAddress("0xdeb8699659bE5d41a0e57E179d6cB42E00B9200C"): new(big.Int).SetUint64(7000000000000000000), - common.HexToAddress("0xB1F05B11Ba3d892EdD00f2e7689779E2B8841827"): new(big.Int).SetUint64(5000000000000000000), - common.HexToAddress("0xF3C456FAAa70fea307A073C3DA9572413c77f58B"): new(big.Int).SetUint64(6000000000000000000), - common.HexToAddress("0x45D3a03E8302de659e7Ea7400C4cfe9CAED8c723"): new(big.Int).SetUint64(6000000000000000000), - common.HexToAddress("0x313c7f7126486fFefCaa9FEA92D968cbf891b80c"): new(big.Int).SetUint64(3000000000000000000), - common.HexToAddress("0x1893eD78480267D1854373A99Cee8dE2E08d430F"): new(big.Int).SetUint64(2000000000000000000), - common.HexToAddress("0xa2E4D94c5923A8dd99c5792A7B0436474c54e1E1"): new(big.Int).SetUint64(2000000000000000000), - common.HexToAddress("0x2a4636A5a1138e35F7f93e81FA56d3c970BC6777"): new(big.Int).SetUint64(1000000000000000000), - } -) diff --git a/state/holders.go b/state/holders.go deleted file mode 100644 index e62405c3..00000000 --- a/state/holders.go +++ /dev/null @@ -1,140 +0,0 @@ -package state - -import ( - "math/big" - "sync" - "sync/atomic" - - "github.com/ethereum/go-ethereum/common" -) - -type HoldersCandidates map[common.Address]*big.Int - -// TokenHolders struct abstracts the current state of a TokenHolders into the -// Census3 HoldersScanner for a specific token. It contains some information -// about the token such as its address or its type. Also includes some atomic -// variables used to store the state of the token holders safely across -// differents goroutines, such as holders list, analyzed blocks or the last -// block analyzed. -type TokenHolders struct { - address common.Address - ctype TokenType - holders sync.Map - blocks sync.Map - lastBlock atomic.Uint64 - synced atomic.Bool - ChainID uint64 - ExternalID string -} - -// Init function fills the given TokenHolders struct with the address and type -// given, also checks the block number provided as done. It returns the -// TokenHolders struct updated. -func (h *TokenHolders) Init(addr common.Address, ctype TokenType, block, chainID uint64, externalID string) *TokenHolders { - h.address = addr - h.ctype = ctype - h.holders = sync.Map{} - h.blocks = sync.Map{} - h.lastBlock.Store(block) - h.synced.Store(false) - h.ChainID = chainID - h.ExternalID = externalID - return h -} - -// Address function returns the given TokenHolders token address. -func (h *TokenHolders) Address() common.Address { - return h.address -} - -// Type function returns the given TokenHolders token type. -func (h *TokenHolders) Type() TokenType { - return h.ctype -} - -// IsReady function returns if the given TokenHolders is ready to be scanned. -// It means that the last block number is greater than 0, at least it will be -// the creation block of the token. -func (h *TokenHolders) IsReady() bool { - return h.lastBlock.Load() > 0 -} - -// Holders function returns the given TokenHolders current token holders -// addresses and its balances. -func (h *TokenHolders) Holders() HoldersCandidates { - holders := HoldersCandidates{} - h.holders.Range(func(rawAddr, rawBalance any) bool { - address, okAddr := rawAddr.(common.Address) - balance, okBalance := rawBalance.(*big.Int) - if !okAddr || !okBalance { - return true - } - - holders[address] = balance - return true - }) - return holders -} - -// Exists function returns if the given TokenHolders list of holders addresss -// includes the provided address. -func (h *TokenHolders) Exists(address common.Address) bool { - _, exists := h.holders.Load(address) - return exists -} - -// Append function appends the holder address and the balance provided into the -// given TokenHolders list of holders. If the holder already exists, it will -// update its balance. -func (h *TokenHolders) Append(addr common.Address, balance *big.Int) { - if currentBalance, exists := h.holders.Load(addr); exists { - h.holders.Store(addr, new(big.Int).Add(currentBalance.(*big.Int), balance)) - return - } - h.holders.Store(addr, balance) -} - -// Del function marks the holder address provided in the list of current -// TokenHolders as false, which means that it will be removed. -func (h *TokenHolders) Del(address common.Address) { - h.holders.Store(address, false) -} - -// FlushHolders function cleans the current list of token holders from the -// current TokenHolders state. -func (h *TokenHolders) FlushHolders() { - h.holders = sync.Map{} -} - -// BlockDone function checks the block number provided as checked appending it -// to the given TokenHolders list of blocks. If it is greater than the current -// TokenHolders block number, it will be updated. -func (h *TokenHolders) BlockDone(blockNumber uint64) { - h.blocks.Store(blockNumber, true) - h.synced.Store(false) - h.lastBlock.CompareAndSwap(h.lastBlock.Load(), blockNumber) -} - -// HasBlock function returns if the provided block number has already checked by -// the given TokenHolders. -func (h *TokenHolders) HasBlock(blockNumber uint64) bool { - _, exists := h.blocks.Load(blockNumber) - return exists -} - -// LastBlock function returns the number of latest block registered. -func (h *TokenHolders) LastBlock() uint64 { - return h.lastBlock.Load() -} - -// Synced function marks the current TokenHolders struct as synced with the -// latest network status. -func (h *TokenHolders) Synced() { - h.synced.Store(true) -} - -// IsSynced function returns if the current TokenHolders instance is already -// synced with the latest network status. -func (h *TokenHolders) IsSynced() bool { - return h.synced.Load() -} diff --git a/state/holders_test.go b/state/holders_test.go deleted file mode 100644 index 95a80482..00000000 --- a/state/holders_test.go +++ /dev/null @@ -1,136 +0,0 @@ -package state - -import ( - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/common" - qt "github.com/frankban/quicktest" -) - -func TestTokenHoldersInit(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 0, "") - c.Assert(th.address.String(), qt.Equals, MonkeysAddress.String()) - c.Assert(th.ctype, qt.Equals, CONTRACT_TYPE_ERC20) - c.Assert(th.lastBlock.Load(), qt.Equals, MonkeysCreationBlock) - c.Assert(th.synced.Load(), qt.IsFalse) -} - -func TestHolders(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - c.Assert(th.address.String(), qt.Equals, MonkeysAddress.String()) - c.Assert(th.ctype, qt.Equals, CONTRACT_TYPE_ERC20) - c.Assert(th.lastBlock.Load(), qt.Equals, MonkeysCreationBlock) - c.Assert(th.synced.Load(), qt.IsFalse) -} - -func TestAppend(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") - holderBalance := new(big.Int).SetUint64(16000000000000000000) - _, exists := th.holders.Load(holderAddr) - c.Assert(exists, qt.IsFalse) - th.Append(holderAddr, holderBalance) - balance, exists := th.holders.Load(holderAddr) - c.Assert(exists, qt.IsTrue) - c.Assert(balance.(*big.Int).String(), qt.Equals, holderBalance.String()) -} - -func TestExists(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") - holderBalance := new(big.Int).SetUint64(16000000000000000000) - c.Assert(th.Exists(holderAddr), qt.IsFalse) - th.Append(holderAddr, holderBalance) - c.Assert(th.Exists(holderAddr), qt.IsTrue) -} - -func TestDel(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") - holderBalance := new(big.Int).SetUint64(16000000000000000000) - th.Append(holderAddr, holderBalance) - balance, exists := th.holders.Load(holderAddr) - c.Assert(exists, qt.IsTrue) - c.Assert(balance.(*big.Int).String(), qt.Equals, holderBalance.String()) - - th.Del(holderAddr) - notRemove, exists := th.holders.Load(holderAddr) - c.Assert(exists, qt.IsTrue) - c.Assert(notRemove.(bool), qt.IsFalse) -} - -func TestFlushHolders(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") - holderBalance := new(big.Int).SetUint64(16000000000000000000) - th.Append(holderAddr, holderBalance) - balance, exists := th.holders.Load(holderAddr) - c.Assert(exists, qt.IsTrue) - c.Assert(balance.(*big.Int).String(), qt.Equals, holderBalance.String()) - - th.FlushHolders() - _, exists = th.holders.Load(holderAddr) - c.Assert(exists, qt.IsFalse) -} - -func TestBlockDone(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - _, exists := th.blocks.Load(MonkeysCreationBlock + 500) - c.Assert(exists, qt.IsFalse) - - th.BlockDone(MonkeysCreationBlock + 500) - processed, exists := th.blocks.Load(MonkeysCreationBlock + 500) - c.Assert(exists, qt.IsTrue) - c.Assert(processed.(bool), qt.IsTrue) -} - -func TestHasBlock(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - c.Assert(th.HasBlock(MonkeysCreationBlock), qt.IsFalse) - th.BlockDone(MonkeysCreationBlock) - c.Assert(th.HasBlock(MonkeysCreationBlock), qt.IsTrue) -} - -func TestLastBlock(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - c.Assert(th.LastBlock(), qt.Equals, MonkeysCreationBlock) - th.BlockDone(MonkeysCreationBlock + 1) - c.Assert(th.LastBlock(), qt.Equals, MonkeysCreationBlock+1) - th.BlockDone(MonkeysCreationBlock + 2) - c.Assert(th.LastBlock(), qt.Equals, MonkeysCreationBlock+2) -} - -func TestSynced(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - c.Assert(th.synced.Load(), qt.IsFalse) - th.Synced() - c.Assert(th.synced.Load(), qt.IsTrue) -} - -func TestIsSynced(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - c.Assert(th.IsSynced(), qt.IsFalse) - th.Synced() - c.Assert(th.IsSynced(), qt.IsTrue) -} diff --git a/state/mod_tidy_workaround.go b/state/mod_tidy_workaround.go deleted file mode 100644 index f003701a..00000000 --- a/state/mod_tidy_workaround.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build only_for_gomod - -package state - -import _ "github.com/btcsuite/btcd/chaincfg/chainhash" diff --git a/state/tokens.go b/state/tokens.go deleted file mode 100644 index 60ff2cbf..00000000 --- a/state/tokens.go +++ /dev/null @@ -1,63 +0,0 @@ -package state - -import ( - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/common" -) - -type TokenType uint64 - -var TokenTypeStringMap = map[TokenType]string{ - CONTRACT_TYPE_UNKNOWN: "unknown", - CONTRACT_TYPE_ERC20: "erc20", - CONTRACT_TYPE_ERC721_BURNED: "erc721burned", - CONTRACT_TYPE_ERC1155: "erc1155", - CONTRACT_TYPE_ERC777: "erc777", - CONTRACT_TYPE_CUSTOM_NATION3_VENATION: "nation3", - CONTRACT_TYPE_CUSTOM_ARAGON_WANT: "want", - CONTRACT_TYPE_ERC721: "erc721", - CONTRACT_TYPE_POAP: "poap", -} - -var TokenTypeIntMap = map[string]TokenType{ - "unknown": CONTRACT_TYPE_UNKNOWN, - "erc20": CONTRACT_TYPE_ERC20, - "erc721": CONTRACT_TYPE_ERC721, - "erc1155": CONTRACT_TYPE_ERC1155, - "erc777": CONTRACT_TYPE_ERC777, - "nation3": CONTRACT_TYPE_CUSTOM_NATION3_VENATION, - "want": CONTRACT_TYPE_CUSTOM_ARAGON_WANT, - "erc721burned": CONTRACT_TYPE_ERC721_BURNED, - "poap": CONTRACT_TYPE_POAP, -} - -func (c TokenType) String() string { - if s, ok := TokenTypeStringMap[c]; ok { - return s - } - return "unknown" -} - -func TokenTypeFromString(s string) TokenType { - if c, ok := TokenTypeIntMap[s]; ok { - return c - } - return CONTRACT_TYPE_UNKNOWN -} - -type TokenData struct { - Address common.Address - Type TokenType - Name string - Symbol string - Decimals uint64 - TotalSupply *big.Int - IconURI string -} - -func (t *TokenData) String() string { - return fmt.Sprintf(`{"address":%s, "type":%s "name":%s,"symbol":%s,"decimals":%d,"totalSupply":%s}`, - t.Address, t.Type.String(), t.Name, t.Symbol, t.Decimals, t.TotalSupply.String()) -} diff --git a/state/tokens_test.go b/state/tokens_test.go deleted file mode 100644 index fc5c0bfe..00000000 --- a/state/tokens_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package state - -import ( - "testing" - - qt "github.com/frankban/quicktest" -) - -func TestTokenTypeString(t *testing.T) { - c := qt.New(t) - for str, tt := range TokenTypeIntMap { - c.Assert(tt.String(), qt.Equals, str) - } - var wrongTokenType TokenType = 1000 - c.Assert(wrongTokenType.String(), qt.Equals, TokenTypeStringMap[CONTRACT_TYPE_UNKNOWN]) -} - -func TestTokenTypeFromString(t *testing.T) { - c := qt.New(t) - for tt, str := range TokenTypeStringMap { - c.Assert(TokenTypeFromString(str), qt.Equals, tt) - } - wrongTokenType := "wrongType" - c.Assert(TokenTypeFromString(wrongTokenType), qt.Equals, CONTRACT_TYPE_UNKNOWN) -} diff --git a/state/web3.go b/state/web3.go deleted file mode 100644 index ac203b67..00000000 --- a/state/web3.go +++ /dev/null @@ -1,671 +0,0 @@ -package state - -import ( - "context" - "fmt" - "math/big" - "strings" - "time" - - "github.com/ethereum/go-ethereum/common" - gethTypes "github.com/ethereum/go-ethereum/core/types" - - want "github.com/vocdoni/census3/contracts/aragon/want" - erc1155 "github.com/vocdoni/census3/contracts/erc/erc1155" - erc20 "github.com/vocdoni/census3/contracts/erc/erc20" - erc721 "github.com/vocdoni/census3/contracts/erc/erc721" - erc777 "github.com/vocdoni/census3/contracts/erc/erc777" - venation "github.com/vocdoni/census3/contracts/nation3/vestedToken" - poap "github.com/vocdoni/census3/contracts/poap" - "github.com/vocdoni/census3/internal" - "github.com/vocdoni/census3/service/web3" - - eth "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/ethclient" - "go.vocdoni.io/dvote/log" -) - -var ( - ErrUnknownTokenType = fmt.Errorf("unknown contract type") - ErrTokenData = fmt.Errorf("unable to get token data") - ErrNoImplementedMethod = fmt.Errorf("this method is not implemented for this token type") - ErrWrongBalanceOfArgs = fmt.Errorf("wrong number of arguments for balanceOf function") - ErrNoNewBlocks = fmt.Errorf("no new blocks") - ErrTransferLogsNotSupported = fmt.Errorf("transferLogs not supported for this token type") - ErrCalcPartialBalancesNotSupported = fmt.Errorf("calcPartialBalances not supported for this token type") -) - -// Web3 holds a reference to a web3 client and a contract, as -// well as storing the contract address, the contract type and -// the network id reported by the endpoint connection -type Web3 struct { - client *ethclient.Client - - contract interface{} - contractType TokenType - contractAddress common.Address -} - -// Init creates and client connection and connects to contract given its address -func (w *Web3) Init(ctx context.Context, web3Endpoint *web3.NetworkEndpoint, - contractAddress common.Address, contractType TokenType, -) error { - var err error - // connect to ethereum endpoint - if web3Endpoint == nil { - return fmt.Errorf("web3 endpoint is nil") - } - w.client, err = web3Endpoint.GetClient(3) - if err != nil { - return err - } - - switch contractType { - case CONTRACT_TYPE_ERC20, - CONTRACT_TYPE_ERC721, - CONTRACT_TYPE_ERC721_BURNED, - CONTRACT_TYPE_ERC1155, - CONTRACT_TYPE_ERC777, - CONTRACT_TYPE_CUSTOM_NATION3_VENATION, - CONTRACT_TYPE_CUSTOM_ARAGON_WANT, - CONTRACT_TYPE_POAP: - w.contractType = contractType - default: - return ErrUnknownTokenType - } - w.contractAddress = contractAddress - if w.contractType == CONTRACT_TYPE_POAP { - w.contractAddress = common.HexToAddress(CONTRACT_POAP_ADDRESS) - } - if w.contract, err = w.NewContract(); err != nil { - return err - } - return nil -} - -func (w *Web3) Close() { - w.client.Close() -} - -func (w *Web3) NewContract() (interface{}, error) { - switch w.contractType { - case CONTRACT_TYPE_ERC20: - return erc20.NewERC20Contract(w.contractAddress, w.client) - case CONTRACT_TYPE_ERC721, CONTRACT_TYPE_ERC721_BURNED: - return erc721.NewERC721Contract(w.contractAddress, w.client) - case CONTRACT_TYPE_POAP: - return poap.NewPOAPContract(w.contractAddress, w.client) - case CONTRACT_TYPE_ERC1155: - return erc1155.NewERC1155Contract(w.contractAddress, w.client) - case CONTRACT_TYPE_ERC777: - return erc777.NewERC777Contract(w.contractAddress, w.client) - case CONTRACT_TYPE_CUSTOM_NATION3_VENATION: - return venation.NewNation3VestedTokenContract(w.contractAddress, w.client) - case CONTRACT_TYPE_CUSTOM_ARAGON_WANT: - return want.NewAragonWrappedANTTokenContract(w.contractAddress, w.client) - default: - return nil, ErrUnknownTokenType - } -} - -// TokenName wraps the name() function contract call -func (w *Web3) TokenName() (string, error) { - switch w.contractType { - case CONTRACT_TYPE_ERC20: - caller := w.contract.(*erc20.ERC20Contract).ERC20ContractCaller - return caller.Name(nil) - case CONTRACT_TYPE_ERC721, CONTRACT_TYPE_ERC721_BURNED: - caller := w.contract.(*erc721.ERC721Contract).ERC721ContractCaller - return caller.Name(nil) - case CONTRACT_TYPE_POAP: - caller := w.contract.(*poap.POAPContract).POAPContractCaller - return caller.Name(nil) - case CONTRACT_TYPE_ERC777: - caller := w.contract.(*erc777.ERC777Contract).ERC777ContractCaller - return caller.Name(nil) - case CONTRACT_TYPE_ERC1155: - return "", nil - case CONTRACT_TYPE_CUSTOM_NATION3_VENATION: - caller := w.contract.(*venation.Nation3VestedTokenContract).Nation3VestedTokenContractCaller - return caller.Name(nil) - case CONTRACT_TYPE_CUSTOM_ARAGON_WANT: - caller := w.contract.(*want.AragonWrappedANTTokenContract).AragonWrappedANTTokenContractCaller - return caller.Name(nil) - } - return "", ErrUnknownTokenType -} - -// TokenSymbol wraps the symbol() function contract call -func (w *Web3) TokenSymbol() (string, error) { - switch w.contractType { - case CONTRACT_TYPE_ERC20: - caller := w.contract.(*erc20.ERC20Contract).ERC20ContractCaller - return caller.Symbol(nil) - case CONTRACT_TYPE_ERC721, CONTRACT_TYPE_ERC721_BURNED: - caller := w.contract.(*erc721.ERC721Contract).ERC721ContractCaller - return caller.Symbol(nil) - case CONTRACT_TYPE_POAP: - return CONTRACT_POAP_SYMBOL, nil - case CONTRACT_TYPE_ERC777: - caller := w.contract.(*erc777.ERC777Contract).ERC777ContractCaller - return caller.Symbol(nil) - case CONTRACT_TYPE_ERC1155: - return "", nil - case CONTRACT_TYPE_CUSTOM_NATION3_VENATION: - caller := w.contract.(*venation.Nation3VestedTokenContract).Nation3VestedTokenContractCaller - return caller.Symbol(nil) - case CONTRACT_TYPE_CUSTOM_ARAGON_WANT: - caller := w.contract.(*want.AragonWrappedANTTokenContract).AragonWrappedANTTokenContractCaller - return caller.Symbol(nil) - } - return "", ErrUnknownTokenType -} - -// TokenDecimals wraps the decimals() function contract call -func (w *Web3) TokenDecimals() (uint8, error) { - switch w.contractType { - case CONTRACT_TYPE_ERC20: - caller := w.contract.(*erc20.ERC20Contract).ERC20ContractCaller - return caller.Decimals(nil) - case CONTRACT_TYPE_ERC721, CONTRACT_TYPE_ERC721_BURNED, CONTRACT_TYPE_POAP: - return 0, nil - case CONTRACT_TYPE_ERC777: - caller := w.contract.(*erc777.ERC777Contract).ERC777ContractCaller - return caller.Decimals(nil) - case CONTRACT_TYPE_ERC1155: - return 0, nil - case CONTRACT_TYPE_CUSTOM_NATION3_VENATION: - caller := w.contract.(*venation.Nation3VestedTokenContract).Nation3VestedTokenContractCaller - decimals, err := caller.Decimals(nil) - if err != nil { - return 0, err - } - return uint8(decimals.Uint64()), nil - case CONTRACT_TYPE_CUSTOM_ARAGON_WANT: - caller := w.contract.(*want.AragonWrappedANTTokenContract).AragonWrappedANTTokenContractCaller - return caller.Decimals(nil) - } - return 0, ErrUnknownTokenType -} - -// TokenTotalSupply wraps the totalSupply function contract call -func (w *Web3) TokenTotalSupply() (*big.Int, error) { - switch w.contractType { - case CONTRACT_TYPE_ERC20: - caller := w.contract.(*erc20.ERC20Contract).ERC20ContractCaller - return caller.TotalSupply(nil) - case CONTRACT_TYPE_ERC721, CONTRACT_TYPE_ERC721_BURNED: - return nil, nil - case CONTRACT_TYPE_POAP: - caller := w.contract.(*poap.POAPContract).POAPContractCaller - return caller.TotalSupply(nil) - case CONTRACT_TYPE_ERC777: - caller := w.contract.(*erc777.ERC777Contract).ERC777ContractCaller - return caller.TotalSupply(nil) - case CONTRACT_TYPE_ERC1155: - return nil, nil - case CONTRACT_TYPE_CUSTOM_NATION3_VENATION: - caller := w.contract.(*venation.Nation3VestedTokenContract).Nation3VestedTokenContractCaller - return caller.TotalSupply(nil) - case CONTRACT_TYPE_CUSTOM_ARAGON_WANT: - caller := w.contract.(*want.AragonWrappedANTTokenContract).AragonWrappedANTTokenContractCaller - return caller.TotalSupply(nil) - } - return nil, ErrUnknownTokenType -} - -func (w *Web3) TokenData() (*TokenData, error) { - td := &TokenData{ - Address: w.contractAddress, - Type: w.contractType, - IconURI: "", - } - var err error - if td.Name, err = w.TokenName(); err != nil { - return nil, ErrTokenData - } - - if td.Symbol, err = w.TokenSymbol(); err != nil { - return nil, ErrTokenData - } - - decimals, err := w.TokenDecimals() - if err != nil { - return nil, ErrTokenData - } - td.Decimals = uint64(decimals) - - if td.TotalSupply, err = w.TokenTotalSupply(); err != nil { - return nil, ErrTokenData - } - return td, nil -} - -// TokenBalanceOf wraps the balanceOf function contract call -// CASE ERC1155: args[0] is the tokenID -// CASE NATION3_VENATION: args[0] is the function to call (0: BalanceOf, 1: BalanceOfAt) -// CASE NATION3_VENATION: args[1] is the block number when calling BalanceOfAt, otherwise it is ignored -// CASE WANT: args[0] is the function to call (0: BalanceOf, 1: BalanceOfAt) -// CASE WANT: args[1] is the block number when calling BalanceOfAt, otherwise it is ignored -func (w *Web3) TokenBalanceOf(tokenHolderAddress common.Address, args ...interface{}) (*big.Int, error) { - switch w.contractType { - case CONTRACT_TYPE_ERC20: - caller := w.contract.(*erc20.ERC20Contract).ERC20ContractCaller - return caller.BalanceOf(nil, tokenHolderAddress) - case CONTRACT_TYPE_ERC721: - caller := w.contract.(*erc721.ERC721Contract).ERC721ContractCaller - return caller.BalanceOf(nil, tokenHolderAddress) - case CONTRACT_TYPE_ERC721_BURNED: - return nil, ErrNoImplementedMethod - case CONTRACT_TYPE_POAP: - return nil, ErrNoImplementedMethod - case CONTRACT_TYPE_ERC777: - caller := w.contract.(*erc777.ERC777Contract).ERC777ContractCaller - return caller.BalanceOf(nil, tokenHolderAddress) - case CONTRACT_TYPE_ERC1155: - if len(args) != 1 { - return nil, ErrWrongBalanceOfArgs - } - caller := w.contract.(*erc1155.ERC1155Contract).ERC1155ContractCaller - return caller.BalanceOf(nil, tokenHolderAddress, big.NewInt(int64(args[0].(uint64)))) - case CONTRACT_TYPE_CUSTOM_NATION3_VENATION: - if len(args) != 2 { - return nil, ErrWrongBalanceOfArgs - } - caller := w.contract.(*venation.Nation3VestedTokenContract).Nation3VestedTokenContractCaller - switch args[0].(int) { - case 0: - return caller.BalanceOf(nil, tokenHolderAddress) - case 1: - return caller.BalanceOfAt(nil, tokenHolderAddress, big.NewInt(int64(args[1].(uint64)))) - } - case CONTRACT_TYPE_CUSTOM_ARAGON_WANT: - if len(args) != 2 { - return nil, ErrWrongBalanceOfArgs - } - caller := w.contract.(*want.AragonWrappedANTTokenContract).AragonWrappedANTTokenContractCaller - switch args[0].(int) { - case 0: - return caller.BalanceOf(nil, tokenHolderAddress) - case 1: - return caller.BalanceOfAt(nil, tokenHolderAddress, big.NewInt(int64(args[1].(uint64)))) - } - } - return nil, ErrUnknownTokenType -} - -// BlockTimestamp function returns the string timestampt of the provided block -// number. The timestamp will be in RFC3339 format. -func (w *Web3) BlockTimestamp(ctx context.Context, blockNumber uint) (string, error) { - blockHeader, err := w.client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) - if err != nil { - return "", err - } - return time.Unix(int64(blockHeader.Time), 0).Format(timeLayout), nil -} - -// BlockRootHash functions returns the root hash of the provided block number in -// bytes. -func (w *Web3) BlockRootHash(ctx context.Context, blockNumber uint) ([]byte, error) { - blockHeader, err := w.client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) - if err != nil { - return nil, err - } - return blockHeader.Root.Bytes(), nil -} - -// LatestBlockNumber function return the number of the latest block of the -// current web3 client network -func (w *Web3) LatestBlockNumber(ctx context.Context) (uint64, error) { - lastBlockHeader, err := w.client.HeaderByNumber(ctx, nil) - if err != nil { - return 0, err - } - return lastBlockHeader.Number.Uint64(), nil -} - -// UpdateTokenHolders function checks the transfer logs of the given contract -// (in the TokenHolders struct) from the given block number. It gets all -// addresses (candidates to holders) and their balances from the given block -// number to the latest block number and submit the results using -// Web3.submitTokenHolders function. -func (w *Web3) UpdateTokenHolders(ctx context.Context, th *TokenHolders) (uint64, error) { - // fetch the last block header - lastBlockNumber, err := w.LatestBlockNumber(ctx) - if err != nil { - return 0, err - } - // check if there are new blocks to scan - toBlock := lastBlockNumber - fromBlockNumber := th.LastBlock() - initialBlockNumber := fromBlockNumber - if fromBlockNumber >= lastBlockNumber { - return fromBlockNumber, ErrNoNewBlocks - } - // check if we need to scan more than MAX_SCAN_BLOCKS_PER_ITERATION - // if so, scan only MAX_SCAN_BLOCKS_PER_ITERATION blocks - if toBlock-fromBlockNumber > MAX_SCAN_BLOCKS_PER_ITERATION { - toBlock = fromBlockNumber + MAX_SCAN_BLOCKS_PER_ITERATION - } - blocks := BLOCKS_TO_SCAN_AT_ONCE - log.Infow("scan iteration", - "address", th.Address().Hex(), - "type", th.Type().String(), - "from", fromBlockNumber, - "to", toBlock) - // get logs and get new candidates to holder. A valid candidate is every - // address with a positive balance at the end of logs review. It requires - // take into account the countability of the candidates' balances. - logCount := 0 - newBlocksMap := make(map[uint64]bool) - holdersCandidates := HoldersCandidates{} - startTime := time.Now() - for fromBlockNumber < toBlock { - select { - // check if we need to close due context signal - case <-ctx.Done(): - log.Warnf("scan graceful canceled by context") - th.BlockDone(fromBlockNumber) - return fromBlockNumber, w.commitTokenHolders(th, holdersCandidates, th.LastBlock()) - default: - log.Debugw("analyzing blocks", - "address", th.Address().Hex(), - "type", th.Type().String(), - "from", fromBlockNumber, - "to", fromBlockNumber+blocks, - "chainID", th.ChainID, - ) - // get transfer logs for the following n blocks - logs, err := w.transferLogs(fromBlockNumber, blocks) - if err != nil { - // if we have too much results, decrease the blocks to scan - if strings.Contains(err.Error(), "query returned more than") { - blocks /= 2 - log.Warnf("too much results on query, decreasing blocks to %d", blocks) - continue - } - return 0, err - } - // after updating the starter block number for the next iteration, - // if there are no logs, mark the starter block as done and proceed - // to the next iteration. - if len(logs) == 0 { - fromBlockNumber += blocks - th.BlockDone(fromBlockNumber) - continue - } - logCount += len(logs) - // iterate over the logs and update the token holders state - for _, currentLog := range logs { - // update the holders candidates with the current log - holdersCandidates, err = w.calcPartialBalances(holdersCandidates, currentLog) - if err != nil { - return fromBlockNumber, err - } - currentLogBlockNumber := currentLog.BlockNumber - newBlocksMap[currentLogBlockNumber] = true - th.BlockDone(currentLogBlockNumber) - } - fromBlockNumber += blocks - th.BlockDone(fromBlockNumber) - // update metrics - internal.TotalNumberOfTransfers.Add(len(logs)) - internal.TransfersByTime.Update(float64(len(logs))) - // check if we need to exit because max logs reached for iteration - if len(holdersCandidates) > MAX_NEW_HOLDER_CANDIDATES_PER_ITERATION { - log.Debug("MAX_NEW_HOLDER_CANDIDATES_PER_ITERATION limit reached... stop scanning") - return fromBlockNumber, w.commitTokenHolders(th, holdersCandidates, fromBlockNumber) - } - if logCount > MAX_SCAN_LOGS_PER_ITERATION { - log.Debug("MAX_SCAN_LOGS_PER_ITERATION limit reached... stop scanning") - return fromBlockNumber, w.commitTokenHolders(th, holdersCandidates, fromBlockNumber) - } - } - } - th.BlockDone(toBlock) - if fromBlockNumber >= lastBlockNumber { - log.Infow("token synced!", "token", w.contractAddress.Hex()) - th.Synced() - } - log.Infow("saving blocks", - "count", len(holdersCandidates), - "logs", logCount, - "blocks/s", 1000*float32(fromBlockNumber-initialBlockNumber)/float32(time.Since(startTime).Milliseconds()), - "took", time.Since(startTime).Seconds(), - "progress", fmt.Sprintf("%d%%", (fromBlockNumber*100)/lastBlockNumber)) - - return toBlock, w.commitTokenHolders(th, holdersCandidates, toBlock) -} - -// getTransferLogs function queries to the web3 endpoint for the transfer logs -// of the token provided, that are included in the range of blocks defined by -// the from block number provided to the following number of blocks given. -func (w *Web3) transferLogs(fromBlock, nblocks uint64) ([]gethTypes.Log, error) { - // create the filter query - query := eth.FilterQuery{ - Addresses: []common.Address{w.contractAddress}, - FromBlock: big.NewInt(int64(fromBlock)), - ToBlock: big.NewInt(int64(fromBlock + nblocks)), - } - // set the topics to filter depending on the contract type - switch w.contractType { - case CONTRACT_TYPE_ERC20, CONTRACT_TYPE_ERC777, CONTRACT_TYPE_ERC721, - CONTRACT_TYPE_ERC721_BURNED: - query.Topics = [][]common.Hash{{common.HexToHash(LOG_TOPIC_ERC20_TRANSFER)}} - case CONTRACT_TYPE_POAP: - return nil, ErrTransferLogsNotSupported - case CONTRACT_TYPE_ERC1155: - query.Topics = [][]common.Hash{ - { - common.HexToHash(LOG_TOPIC_ERC1155_TRANSFER_SINGLE), - common.HexToHash(LOG_TOPIC_ERC1155_TRANSFER_BATCH), - }, - } - case CONTRACT_TYPE_CUSTOM_NATION3_VENATION: - query.Topics = [][]common.Hash{ - { - common.HexToHash(LOG_TOPIC_VENATION_DEPOSIT), - common.HexToHash(LOG_TOPIC_VENATION_WITHDRAW), - }, - } - case CONTRACT_TYPE_CUSTOM_ARAGON_WANT: - query.Topics = [][]common.Hash{ - { - common.HexToHash(LOG_TOPIC_WANT_DEPOSIT), - common.HexToHash(LOG_TOPIC_WANT_WITHDRAWAL), - }, - } - default: - return nil, ErrUnknownTokenType - } - // execute the filter query - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - return w.client.FilterLogs(ctx, query) -} - -// calcPartialBalances function calculates the partial balances of the given -// holder candidates with the values of the given log. It uses the appropriate -// functions for the given token type. If the holder address is the 'from' -// address, the transaction value is added to the current balance (if it does -// not exist, it is set to the received value). If the holder address is the -// 'to' address, the transaction value is subtracted from the current balance -// (if it does not exist, it is set to the received value, but in negative). -// This behaviour allows to keep track of the partial balance of each holder -// candidate for a batch of logs or blocks, and then update the total balance -// in a single operation. -func (w *Web3) calcPartialBalances(hc HoldersCandidates, currentLog gethTypes.Log) (HoldersCandidates, error) { - // update the token holders state with the log data - switch w.contractType { - case CONTRACT_TYPE_ERC20: - filter := w.contract.(*erc20.ERC20Contract).ERC20ContractFilterer - logData, err := filter.ParseTransfer(currentLog) - if err != nil { - return hc, err - } - if toBalance, exists := hc[logData.To]; exists { - hc[logData.To] = new(big.Int).Add(toBalance, logData.Value) - } else { - hc[logData.To] = logData.Value - } - if fromBalance, exists := hc[logData.From]; exists { - hc[logData.From] = new(big.Int).Sub(fromBalance, logData.Value) - } else { - hc[logData.From] = new(big.Int).Neg(logData.Value) - } - case CONTRACT_TYPE_ERC777: // stores the total count per address, not all identifiers - filter := w.contract.(*erc777.ERC777Contract).ERC777ContractFilterer - logData, err := filter.ParseTransfer(currentLog) - if err != nil { - return hc, err - } - if toBalance, exists := hc[logData.To]; exists { - hc[logData.To] = new(big.Int).Add(toBalance, big.NewInt(1)) - } else { - hc[logData.To] = big.NewInt(1) - } - if fromBalance, exists := hc[logData.From]; exists { - hc[logData.From] = new(big.Int).Sub(fromBalance, big.NewInt(1)) - } else { - hc[logData.From] = big.NewInt(-1) - } - case CONTRACT_TYPE_ERC721: // stores the total count per address, not all identifiers - filter := w.contract.(*erc721.ERC721Contract).ERC721ContractFilterer - logData, err := filter.ParseTransfer(currentLog) - if err != nil { - return hc, err - } - if toBalance, exists := hc[logData.To]; exists { - hc[logData.To] = new(big.Int).Add(toBalance, big.NewInt(1)) - } else { - hc[logData.To] = big.NewInt(1) - } - if fromBalance, exists := hc[logData.From]; exists { - hc[logData.From] = new(big.Int).Sub(fromBalance, big.NewInt(1)) - } else { - hc[logData.From] = big.NewInt(-1) - } - case CONTRACT_TYPE_ERC721_BURNED: - filter := w.contract.(*erc721.ERC721Contract).ERC721ContractFilterer - logData, err := filter.ParseTransfer(currentLog) - if err != nil { - return hc, err - } - if logData.To == common.HexToAddress(NULL_ADDRESS) { - if fromBalance, exists := hc[logData.From]; exists { - hc[logData.From] = new(big.Int).Add(fromBalance, big.NewInt(1)) - } else { - hc[logData.From] = big.NewInt(1) - } - } - case CONTRACT_TYPE_POAP: - return nil, ErrCalcPartialBalancesNotSupported - case CONTRACT_TYPE_CUSTOM_NATION3_VENATION: - // This token contract is a bit special, token balances - // are updated every block based on the contract state. - switch currentLog.Topics[0] { - case common.HexToHash(LOG_TOPIC_VENATION_DEPOSIT): - provider := common.HexToAddress(currentLog.Topics[1].Hex()) - value := big.NewInt(0).SetBytes(currentLog.Data[:32]) - if toBalance, exists := hc[provider]; exists { - hc[provider] = new(big.Int).Add(toBalance, value) - } else { - hc[provider] = value - } - case common.HexToHash(LOG_TOPIC_VENATION_WITHDRAW): - provider := common.HexToAddress(currentLog.Topics[1].Hex()) - value := big.NewInt(0).SetBytes(currentLog.Data[:32]) - if fromBalance, exists := hc[provider]; exists { - hc[provider] = new(big.Int).Sub(fromBalance, value) - } else { - hc[provider] = new(big.Int).Neg(value) - } - } - case CONTRACT_TYPE_CUSTOM_ARAGON_WANT: - filter := w.contract.(*want.AragonWrappedANTTokenContract).AragonWrappedANTTokenContractFilterer - switch currentLog.Topics[0] { - case common.HexToHash(LOG_TOPIC_WANT_DEPOSIT): - logData, err := filter.ParseDeposit(currentLog) - if err != nil { - return hc, err - } - if toBalance, exists := hc[logData.Entity]; exists { - hc[logData.Entity] = new(big.Int).Add(toBalance, logData.Amount) - } else { - hc[logData.Entity] = logData.Amount - } - case common.HexToHash(LOG_TOPIC_WANT_WITHDRAWAL): - logData, err := filter.ParseWithdrawal(currentLog) - if err != nil { - return hc, err - } - if fromBalance, exists := hc[logData.Entity]; exists { - hc[logData.Entity] = new(big.Int).Sub(fromBalance, logData.Amount) - } else { - hc[logData.Entity] = new(big.Int).Neg(logData.Amount) - } - } - } - return hc, nil -} - -// commitTokenHolders function checks each candidate to token holder provided, -// and removes any with a zero balance before store them. It also checks the -// balances of the current holders, deleting those with no funds. -func (w *Web3) commitTokenHolders(th *TokenHolders, candidates HoldersCandidates, blockNumber uint64) error { - // remove null address from candidates - delete(candidates, common.HexToAddress(NULL_ADDRESS)) - // update the token holders state with the candidates data - for addr, balance := range candidates { - th.Append(addr, balance) - } - // update last analysed block metric - lastBlockCounter := internal.LastAnalysedBlockByChain.GetOrCreateCounter( - fmt.Sprintf("%s%d", internal.LastAnalysedBlockByChainPrefix, th.ChainID)) - if lastBlockCounter.Get() < blockNumber { - lastBlockCounter.Set(blockNumber) - } - return nil -} - -// ContractCreationBlock function calculates the block number where the -// current was created. It tries to calculate it using the first block (0) and -// the current last block. -func (w *Web3) ContractCreationBlock(ctx context.Context) (uint64, error) { - lastBlockHeader, err := w.client.HeaderByNumber(ctx, nil) - if err != nil { - return 0, err - } - return w.creationBlockInRange(ctx, 0, lastBlockHeader.Number.Uint64()) -} - -// creationBlockInRange function finds the block number of a contract between -// the bounds provided as start and end blocks. -func (w *Web3) creationBlockInRange(ctx context.Context, start, end uint64) (uint64, error) { - // if both block numbers are equal, return its value as birthblock - if start == end { - return start, nil - } - // find the middle block between start and end blocks and get the contract - // code at this block - midBlock := (start + end) / 2 - codeLen, err := w.SourceCodeLenAt(ctx, midBlock) - if err != nil && !strings.Contains(err.Error(), fmt.Sprintf("No state available for block %d", midBlock)) { - return 0, err - } - // if any code is found, keep trying with the lower half of blocks until - // find the first. if not, keep trying with the upper half - if codeLen > 2 { - return w.creationBlockInRange(ctx, start, midBlock) - } else { - return w.creationBlockInRange(ctx, midBlock+1, end) - } -} - -// SourceCodeLenAt function returns the length of the current contract bytecode -// at the block number provided. -func (w *Web3) SourceCodeLenAt(ctx context.Context, atBlockNumber uint64) (int, error) { - blockNumber := new(big.Int).SetUint64(atBlockNumber) - sourceCode, err := w.client.CodeAt(ctx, w.contractAddress, blockNumber) - return len(sourceCode), err -} diff --git a/state/web3_test.go b/state/web3_test.go deleted file mode 100644 index 54f51a16..00000000 --- a/state/web3_test.go +++ /dev/null @@ -1,326 +0,0 @@ -package state - -import ( - "context" - "math/big" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - qt "github.com/frankban/quicktest" - "github.com/vocdoni/census3/service/web3" -) - -var web3URI, _ = web3.TestNetworkEndpoint() - -func TestWeb3Init(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - c.Assert(new(Web3).Init(ctx, nil, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNotNil) - c.Assert(new(Web3).Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) -} - -func TestNewContract(t *testing.T) { - c := qt.New(t) - w := new(Web3) - _, err := w.NewContract() - c.Assert(err, qt.IsNotNil) - - w.contractType = CONTRACT_TYPE_UNKNOWN - _, err = w.NewContract() - c.Assert(err, qt.IsNotNil) - - w.contractType = CONTRACT_TYPE_ERC20 - _, err = w.NewContract() - c.Assert(err, qt.IsNil) -} - -func TestTokenName(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, common.HexToAddress("0x0"), CONTRACT_TYPE_ERC20), qt.IsNil) - _, err := w.TokenName() - c.Assert(err, qt.IsNotNil) - - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - name, err := w.TokenName() - c.Assert(err, qt.IsNil) - c.Assert(name, qt.Equals, MonkeysName) -} - -func TestTokenSymbol(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, common.HexToAddress("0x0"), CONTRACT_TYPE_ERC20), qt.IsNil) - _, err := w.TokenSymbol() - c.Assert(err, qt.IsNotNil) - - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - symbol, err := w.TokenSymbol() - c.Assert(err, qt.IsNil) - c.Assert(symbol, qt.Equals, MonkeysSymbol) -} - -func TestTokenDecimals(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, common.HexToAddress("0x0"), CONTRACT_TYPE_ERC20), qt.IsNil) - _, err := w.TokenDecimals() - c.Assert(err, qt.IsNotNil) - - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - decimals, err := w.TokenDecimals() - c.Assert(err, qt.IsNil) - c.Assert(int64(decimals), qt.Equals, MonkeysDecimals) -} - -func TestTokenTotalSupply(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - totalSupply, err := w.TokenTotalSupply() - c.Assert(err, qt.IsNil) - c.Assert(totalSupply.String(), qt.Equals, MonkeysTotalSupply.String()) -} - -func TestTokenData(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, common.HexToAddress("0x0"), CONTRACT_TYPE_ERC20), qt.IsNil) - _, err := w.TokenData() - c.Assert(err, qt.IsNotNil) - - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - data, err := w.TokenData() - c.Assert(err, qt.IsNil) - c.Assert(data.Address, qt.Equals, MonkeysAddress) - c.Assert(data.Type, qt.Equals, CONTRACT_TYPE_ERC20) - c.Assert(data.Name, qt.Equals, MonkeysName) - c.Assert(data.Symbol, qt.Equals, MonkeysSymbol) - c.Assert(int64(data.Decimals), qt.Equals, MonkeysDecimals) - c.Assert(data.TotalSupply.String(), qt.Equals, MonkeysTotalSupply.String()) -} - -func TestTokenBalanceOf(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - - holderAddress := common.HexToAddress("0xB1F05B11Ba3d892EdD00f2e7689779E2B8841827") - balance, err := w.TokenBalanceOf(holderAddress) - c.Assert(err, qt.IsNil) - c.Assert(balance.String(), qt.Equals, MonkeysHolders[holderAddress].String()) - - balance, err = w.TokenBalanceOf(common.HexToAddress("0x0")) - c.Assert(err, qt.IsNil) - c.Assert(balance.String(), qt.Equals, "0") -} - -func TestBlockTimestamp(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - expected, err := time.Parse(timeLayout, "2023-04-27T19:21:24+02:00") - c.Assert(err, qt.IsNil) - timestamp, err := w.BlockTimestamp(ctx, uint(MonkeysCreationBlock)) - c.Assert(err, qt.IsNil) - result, err := time.Parse(timeLayout, timestamp) - c.Assert(err, qt.IsNil) - c.Assert(expected.Equal(result), qt.IsTrue) -} - -func TestBlockRootHash(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - expected := common.HexToHash("0x541528e4030f29a87e81ea034e485ede7ea3086784212a3a4863a7de32415de0") - bhash, err := w.BlockRootHash(ctx, uint(MonkeysCreationBlock)) - c.Assert(err, qt.IsNil) - c.Assert(common.BytesToHash(bhash), qt.ContentEquals, expected) -} - -func TestLatestBlockNumber(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - blockNumber, err := w.LatestBlockNumber(ctx) - c.Assert(err, qt.IsNil) - c.Assert(uint64(blockNumber) > MonkeysCreationBlock, qt.IsTrue) -} - -func TestUpdateTokenHolders(t *testing.T) { - c := qt.New(t) - - th := new(TokenHolders) - th = th.Init(MonkeysAddress, CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - w3 := Web3{} - ctx, cancel := context.WithTimeout(context.Background(), 3000*time.Second) - defer cancel() - - c.Assert(w3.Init(ctx, web3URI, th.Address(), th.Type()), qt.IsNil) - - current, end := MonkeysCreationBlock, MonkeysCreationBlock+1000 - var err error - for current < end { - current, err = w3.UpdateTokenHolders(ctx, th) - if err != nil { - c.Assert(err, qt.ErrorIs, ErrNoNewBlocks) - } - time.Sleep(time.Second) - } - - for addr, balance := range th.Holders() { - expectedBalance, ok := MonkeysHolders[addr] - c.Assert(ok, qt.IsTrue) - c.Assert(balance.String(), qt.Equals, expectedBalance.String()) - } -} - -func Test_transferLogs(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - - logs, err := w.transferLogs(MonkeysCreationBlock, MonkeysCreationBlock+500) - c.Assert(err, qt.IsNil) - c.Assert(logs, qt.HasLen, len(MonkeysHolders)) -} - -func Test_calcPartialBalances(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - - logs, err := w.transferLogs(MonkeysCreationBlock, MonkeysCreationBlock+500) - c.Assert(err, qt.IsNil) - - hc := HoldersCandidates{} - for _, log := range logs { - hc, err = w.calcPartialBalances(hc, log) - c.Assert(err, qt.IsNil) - } - for addr, balance := range MonkeysHolders { - res, ok := hc[addr] - c.Assert(ok, qt.IsTrue) - c.Assert(res.String(), qt.Equals, balance.String(), qt.Commentf(addr.String())) - } -} - -func Test_commitTokenHolders(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - - hc := HoldersCandidates(MonkeysHolders) - th := new(TokenHolders).Init(MonkeysAddress, CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - c.Assert(w.commitTokenHolders(th, hc, MonkeysCreationBlock+1000), qt.IsNil) - - c.Assert(th.LastBlock(), qt.Equals, MonkeysCreationBlock) - for addr, balance := range hc { - c.Assert(th.Exists(addr), qt.IsTrue) - val, ok := th.holders.Load(addr) - c.Logf("addr: %s, balance: %d, val: %d", addr.String(), balance, val.(*big.Int)) - c.Assert(ok, qt.IsTrue) - c.Assert(val.(*big.Int).String(), qt.Equals, balance.String()) - } -} - -func TestCreationBlock(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, common.HexToAddress(""), CONTRACT_TYPE_ERC20), qt.IsNil) - - // for an invalid contract address, returns the latest block number, the - // test uses a range of block numbers to cover also the case where any block - // is mined during test execution - creationBlock, err := w.ContractCreationBlock(ctx) - c.Assert(err, qt.IsNil) - latestBlock, err := w.LatestBlockNumber(ctx) - c.Assert(err, qt.IsNil) - c.Assert(creationBlock > latestBlock-5 && creationBlock < latestBlock+5, qt.IsTrue) - - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - creationBlock, err = w.ContractCreationBlock(ctx) - c.Assert(err, qt.IsNil) - c.Assert(creationBlock, qt.Equals, MonkeysCreationBlock) -} - -func Test_creationBlockInRange(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - - blockNumber, err := w.creationBlockInRange(ctx, 0, 10) - c.Assert(err, qt.IsNil) - c.Assert(blockNumber, qt.Equals, uint64(10)) - - blockNumber, err = w.creationBlockInRange(ctx, 0, 1) - c.Assert(err, qt.IsNil) - c.Assert(blockNumber, qt.Equals, uint64(1)) - - blockNumber, err = w.creationBlockInRange(ctx, 0, 9000000) - c.Assert(err, qt.IsNil) - c.Assert(blockNumber, qt.Equals, MonkeysCreationBlock) -} - -func TestSourceCodeLenAt(t *testing.T) { - c := qt.New(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - w := new(Web3) - c.Assert(w.Init(ctx, web3URI, MonkeysAddress, CONTRACT_TYPE_ERC20), qt.IsNil) - - codeLen, err := w.SourceCodeLenAt(ctx, MonkeysCreationBlock) - c.Assert(err, qt.IsNil) - c.Assert(codeLen > 2, qt.IsTrue) - - codeLen, err = w.SourceCodeLenAt(ctx, MonkeysCreationBlock-1) - c.Assert(err, qt.IsNil) - c.Assert(codeLen > 2, qt.IsFalse) -} From 6f8722d59d114e50c0841f8102d0416e0f53d29c Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Wed, 17 Jan 2024 11:32:27 +0100 Subject: [PATCH 04/35] fixing linter --- service/providers/web3/const.go | 3 ++- service/providers/web3/erc20_provider.go | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/service/providers/web3/const.go b/service/providers/web3/const.go index 2f3b5d03..59cb6c57 100644 --- a/service/providers/web3/const.go +++ b/service/providers/web3/const.go @@ -5,6 +5,7 @@ import "time" const ( DefaultMaxWeb3ClientRetries = 3 ) + const ( shortNameSourceUri = "https://chainid.network/chains_mini.json" checkNetworkEndpointsTimeout = time.Second * 10 @@ -37,4 +38,4 @@ const ( LOG_TOPIC_WANT_DEPOSIT = "e1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c" LOG_TOPIC_WANT_WITHDRAWAL = "7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65" // Add more topics here -) \ No newline at end of file +) diff --git a/service/providers/web3/erc20_provider.go b/service/providers/web3/erc20_provider.go index fe3e68fd..d9b8d4bd 100644 --- a/service/providers/web3/erc20_provider.go +++ b/service/providers/web3/erc20_provider.go @@ -88,7 +88,9 @@ func (p *ERC20HolderProvider) SetRef(iref any) error { return nil } -func (p *ERC20HolderProvider) SetLastBalances(ctx context.Context, id []byte, balances map[common.Address]*big.Int, from uint64) error { +func (p *ERC20HolderProvider) SetLastBalances(ctx context.Context, id []byte, + balances map[common.Address]*big.Int, from uint64, +) error { p.balancesMtx.Lock() defer p.balancesMtx.Unlock() @@ -263,7 +265,9 @@ func (p *ERC20HolderProvider) BalanceOf(addr common.Address, _ []byte) (*big.Int return p.contract.ERC20ContractCaller.BalanceOf(nil, addr) } -func (p *ERC20HolderProvider) BalanceAt(ctx context.Context, addr common.Address, _ []byte, blockNumber uint64) (*big.Int, error) { +func (p *ERC20HolderProvider) BalanceAt(ctx context.Context, addr common.Address, + _ []byte, blockNumber uint64, +) (*big.Int, error) { return p.client.BalanceAt(ctx, addr, new(big.Int).SetUint64(blockNumber)) } From 778bc80ef54bc3f31346bab28f00354884d02bd7 Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Wed, 17 Jan 2024 11:35:10 +0100 Subject: [PATCH 05/35] go.mod updated --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index f6a57b8b..e9b901c8 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.21.1 require ( github.com/VictoriaMetrics/metrics v1.24.0 - github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 github.com/ethereum/go-ethereum v1.13.4 github.com/frankban/quicktest v1.14.6 github.com/google/uuid v1.4.0 @@ -34,6 +33,7 @@ require ( github.com/bits-and-blooms/bitset v1.7.0 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/ceramicnetwork/go-dag-jose v0.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect From 904da8b8025fe0e850c6b7c45401b127b325efce Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Wed, 17 Jan 2024 12:51:36 +0100 Subject: [PATCH 06/35] fixing tests --- db/queries/tokens.sql | 4 ++- db/sqlc/blocks.sql.go | 2 +- db/sqlc/censuses.sql.go | 2 +- db/sqlc/db.go | 2 +- db/sqlc/holders.sql.go | 2 +- db/sqlc/models.go | 2 +- db/sqlc/strategies.sql.go | 2 +- db/sqlc/tokenTypes.sql.go | 2 +- db/sqlc/tokens.sql.go | 13 +++++++-- service/helper_test.go | 2 ++ service/holder_scanner_test.go | 36 +++++++++++++++++------- service/holders_scanner.go | 3 ++ service/providers/web3/erc20_provider.go | 9 ++++-- 13 files changed, 59 insertions(+), 22 deletions(-) diff --git a/db/queries/tokens.sql b/db/queries/tokens.sql index c5e1256d..ef0d5832 100644 --- a/db/queries/tokens.sql +++ b/db/queries/tokens.sql @@ -85,7 +85,9 @@ WHERE id = sqlc.arg(id) -- name: UpdateTokenCreationBlock :execresult UPDATE tokens SET creation_block = sqlc.arg(creation_block) -WHERE id = sqlc.arg(id); +WHERE id = sqlc.arg(id) + AND chain_id = sqlc.arg(chain_id) + AND external_id = sqlc.arg(external_id); -- name: UpdateTokenDefaultStrategy :execresult UPDATE tokens diff --git a/db/sqlc/blocks.sql.go b/db/sqlc/blocks.sql.go index 2b39e6ed..87d84ea3 100644 --- a/db/sqlc/blocks.sql.go +++ b/db/sqlc/blocks.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.24.0 // source: blocks.sql package queries diff --git a/db/sqlc/censuses.sql.go b/db/sqlc/censuses.sql.go index 852c8bf5..ed1e74f9 100644 --- a/db/sqlc/censuses.sql.go +++ b/db/sqlc/censuses.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.24.0 // source: censuses.sql package queries diff --git a/db/sqlc/db.go b/db/sqlc/db.go index ef8b0c29..d4cdb252 100644 --- a/db/sqlc/db.go +++ b/db/sqlc/db.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.24.0 package queries diff --git a/db/sqlc/holders.sql.go b/db/sqlc/holders.sql.go index b6843c54..b9c6fff3 100644 --- a/db/sqlc/holders.sql.go +++ b/db/sqlc/holders.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.24.0 // source: holders.sql package queries diff --git a/db/sqlc/models.go b/db/sqlc/models.go index 88d80655..2f288b5f 100644 --- a/db/sqlc/models.go +++ b/db/sqlc/models.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.24.0 package queries diff --git a/db/sqlc/strategies.sql.go b/db/sqlc/strategies.sql.go index 5d85c1d2..8b7f3b9c 100644 --- a/db/sqlc/strategies.sql.go +++ b/db/sqlc/strategies.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.24.0 // source: strategies.sql package queries diff --git a/db/sqlc/tokenTypes.sql.go b/db/sqlc/tokenTypes.sql.go index 53f28194..3d4ecc67 100644 --- a/db/sqlc/tokenTypes.sql.go +++ b/db/sqlc/tokenTypes.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.24.0 // source: tokenTypes.sql package queries diff --git a/db/sqlc/tokens.sql.go b/db/sqlc/tokens.sql.go index bcd60c16..df188401 100644 --- a/db/sqlc/tokens.sql.go +++ b/db/sqlc/tokens.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.24.0 // source: tokens.sql package queries @@ -595,15 +595,24 @@ const updateTokenCreationBlock = `-- name: UpdateTokenCreationBlock :execresult UPDATE tokens SET creation_block = ? WHERE id = ? + AND chain_id = ? + AND external_id = ? ` type UpdateTokenCreationBlockParams struct { CreationBlock int64 ID annotations.Address + ChainID uint64 + ExternalID string } func (q *Queries) UpdateTokenCreationBlock(ctx context.Context, arg UpdateTokenCreationBlockParams) (sql.Result, error) { - return q.db.ExecContext(ctx, updateTokenCreationBlock, arg.CreationBlock, arg.ID) + return q.db.ExecContext(ctx, updateTokenCreationBlock, + arg.CreationBlock, + arg.ID, + arg.ChainID, + arg.ExternalID, + ) } const updateTokenDefaultStrategy = `-- name: UpdateTokenDefaultStrategy :execresult diff --git a/service/helper_test.go b/service/helper_test.go index 51d2b102..159200a2 100644 --- a/service/helper_test.go +++ b/service/helper_test.go @@ -11,10 +11,12 @@ import ( "github.com/vocdoni/census3/db" "github.com/vocdoni/census3/db/annotations" queries "github.com/vocdoni/census3/db/sqlc" + "github.com/vocdoni/census3/service/providers" ) var ( MonkeysAddress = common.HexToAddress("0xF530280176385AF31177D78BbFD5eA3f6D07488A") + MonkeysType = providers.CONTRACT_TYPE_ERC20 MonkeysCreationBlock = uint64(8901659) MonkeysSymbol = "MON" MonkeysName = "Monkeys" diff --git a/service/holder_scanner_test.go b/service/holder_scanner_test.go index b82316ea..dd314f8e 100644 --- a/service/holder_scanner_test.go +++ b/service/holder_scanner_test.go @@ -20,15 +20,26 @@ var ( web3Endpoints = map[uint64]*web3.NetworkEndpoint{ web3endpoint.ChainID: web3endpoint, } + holdersProviders = map[uint64]providers.HolderProvider{ + MonkeysType: new(web3.ERC20HolderProvider), + } ) +func init() { + if err := holdersProviders[MonkeysType].Init(web3.Web3ProviderConfig{ + Endpoints: web3Endpoints, + }); err != nil { + panic(err) + } +} + func TestNewHolderScanner(t *testing.T) { c := qt.New(t) testdb := StartTestDB(t) defer testdb.Close(t) - hs, err := NewHoldersScanner(testdb.db, web3Endpoints, nil, 20) + hs, err := NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) c.Assert(err, qt.IsNil) c.Assert(hs.lastBlock, qt.Equals, uint64(0)) @@ -41,11 +52,11 @@ func TestNewHolderScanner(t *testing.T) { }) c.Assert(err, qt.IsNil) - hs, err = NewHoldersScanner(testdb.db, web3Endpoints, nil, 20) + hs, err = NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) c.Assert(err, qt.IsNil) c.Assert(hs.lastBlock, qt.Equals, uint64(1000)) - _, err = NewHoldersScanner(nil, web3Endpoints, nil, 20) + _, err = NewHoldersScanner(nil, web3Endpoints, holdersProviders, 20) c.Assert(err, qt.IsNotNil) } @@ -58,7 +69,7 @@ func TestHolderScannerStart(t *testing.T) { defer testdb.Close(t) twg.Add(1) - hs, err := NewHoldersScanner(testdb.db, web3Endpoints, nil, 20) + hs, err := NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) c.Assert(err, qt.IsNil) go func() { hs.Start(ctx) @@ -75,7 +86,7 @@ func Test_getTokensToScan(t *testing.T) { testdb := StartTestDB(t) defer testdb.Close(t) - hs, err := NewHoldersScanner(testdb.db, web3Endpoints, nil, 20) + hs, err := NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) c.Assert(err, qt.IsNil) c.Assert(hs.getTokensToScan(), qt.IsNil) @@ -98,6 +109,7 @@ func Test_getTokensToScan(t *testing.T) { err = hs.getTokensToScan() c.Assert(err, qt.IsNil) + c.Assert(hs.calcTokenCreationBlock(ctx, 1), qt.IsNil) c.Assert(hs.tokens[1].IsReady(), qt.IsTrue) c.Assert(hs.tokens[1].Address().String(), qt.Equals, common.HexToAddress("0x2").String()) } @@ -108,7 +120,7 @@ func Test_saveHolders(t *testing.T) { testdb := StartTestDB(t) defer testdb.Close(t) - hs, err := NewHoldersScanner(testdb.db, web3Endpoints, nil, 20) + hs, err := NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) c.Assert(err, qt.IsNil) th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") @@ -166,7 +178,7 @@ func Test_scanHolders(t *testing.T) { testdb := StartTestDB(t) defer testdb.Close(t) - hs, err := NewHoldersScanner(testdb.db, web3Endpoints, nil, 20) + hs, err := NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) c.Assert(err, qt.IsNil) // token does not exists @@ -202,10 +214,10 @@ func Test_calcTokenCreationBlock(t *testing.T) { testdb := StartTestDB(t) defer testdb.Close(t) - hs, err := NewHoldersScanner(testdb.db, web3Endpoints, nil, 20) + hs, err := NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) hs.tokens = append(hs.tokens, new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, 0, 5, "")) c.Assert(err, qt.IsNil) - c.Assert(hs.calcTokenCreationBlock(context.Background(), 5), qt.IsNotNil) + c.Assert(hs.calcTokenCreationBlock(context.Background(), 0), qt.IsNotNil) _, err = testdb.db.QueriesRW.CreateToken(context.Background(), testTokenParams( MonkeysAddress.String(), MonkeysName, MonkeysSymbol, MonkeysCreationBlock, @@ -213,7 +225,11 @@ func Test_calcTokenCreationBlock(t *testing.T) { c.Assert(err, qt.IsNil) c.Assert(hs.calcTokenCreationBlock(context.Background(), 0), qt.IsNil) - token, err := testdb.db.QueriesRW.TokenByID(context.Background(), MonkeysAddress.Bytes()) + token, err := testdb.db.QueriesRO.TokenByIDAndChainID(context.Background(), + queries.TokenByIDAndChainIDParams{ + ID: MonkeysAddress.Bytes(), + ChainID: 5, + }) c.Assert(err, qt.IsNil) c.Assert(uint64(token.CreationBlock), qt.Equals, MonkeysCreationBlock) } diff --git a/service/holders_scanner.go b/service/holders_scanner.go index 226d2d16..8a53eb47 100644 --- a/service/holders_scanner.go +++ b/service/holders_scanner.go @@ -533,6 +533,7 @@ func (s *HoldersScanner) calcTokenCreationBlock(ctx context.Context, index int) } addr := s.tokens[index].Address() chainID := s.tokens[index].ChainID + externalID := s.tokens[index].ExternalID // set a deadline of 10 seconds from the current context ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() @@ -564,6 +565,8 @@ func (s *HoldersScanner) calcTokenCreationBlock(ctx context.Context, index int) _, err = s.db.QueriesRW.UpdateTokenCreationBlock(ctx, queries.UpdateTokenCreationBlockParams{ ID: addr.Bytes(), + ChainID: chainID, + ExternalID: externalID, CreationBlock: int64(creationBlock), }) if err != nil { diff --git a/service/providers/web3/erc20_provider.go b/service/providers/web3/erc20_provider.go index d9b8d4bd..e1a887a7 100644 --- a/service/providers/web3/erc20_provider.go +++ b/service/providers/web3/erc20_provider.go @@ -72,15 +72,20 @@ func (p *ERC20HolderProvider) SetRef(iref any) error { if err != nil { return errors.Join(ErrConnectingToWeb3Client, fmt.Errorf("[ERC20] %s: %w", ref.HexAddress, err)) } - // parse the address and initialize the contract + // set the client, parse the address and initialize the contract + p.client = client address := common.HexToAddress(ref.HexAddress) if p.contract, err = erc20.NewERC20Contract(address, client); err != nil { return errors.Join(ErrInitializingContract, fmt.Errorf("[ERC20] %s: %w", p.address, err)) } // reset the internal attributes - p.client = client p.address = address p.chainID = ref.ChainID + p.name = "" + p.symbol = "" + p.decimals = 0 + p.totalSupply = nil + p.creationBlock = 0 // reset balances p.balancesMtx.Lock() defer p.balancesMtx.Unlock() From 3aa49ce12ec5eeaff8e2c23ad967be1b0f42ec08 Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Mon, 22 Jan 2024 13:28:23 +0100 Subject: [PATCH 07/35] scanner refactoring and simplification --- api/api.go | 4 +- api/helpers.go | 4 +- api/holders.go | 2 +- api/tokens.go | 4 +- cmd/census3/main.go | 17 +- {service => scanner}/const.go | 9 +- .../providers/holders_provider.go | 0 .../providers/poap/poap_provider.go | 2 +- .../providers/poap/poap_provider_test.go | 0 {service => scanner}/providers/types.go | 0 {service => scanner}/providers/web3/const.go | 0 .../providers/web3/endpoint.go | 0 .../providers/web3/endpoint_test.go | 0 .../providers/web3/erc20_provider.go | 2 +- {service => scanner}/providers/web3/errors.go | 0 .../providers/web3/helpers.go | 2 +- .../providers/web3/web3_provider.go | 0 scanner/scanner.go | 470 ++++++++++++++ service/helper_test.go | 78 --- service/holder_scanner_test.go | 235 ------- service/holders_scanner.go | 577 ------------------ service/tokenholders.go | 140 ----- service/tokenholders_test.go | 137 ----- 23 files changed, 494 insertions(+), 1189 deletions(-) rename {service => scanner}/const.go (65%) rename {service => scanner}/providers/holders_provider.go (100%) rename {service => scanner}/providers/poap/poap_provider.go (99%) rename {service => scanner}/providers/poap/poap_provider_test.go (100%) rename {service => scanner}/providers/types.go (100%) rename {service => scanner}/providers/web3/const.go (100%) rename {service => scanner}/providers/web3/endpoint.go (100%) rename {service => scanner}/providers/web3/endpoint_test.go (100%) rename {service => scanner}/providers/web3/erc20_provider.go (99%) rename {service => scanner}/providers/web3/errors.go (100%) rename {service => scanner}/providers/web3/helpers.go (97%) rename {service => scanner}/providers/web3/web3_provider.go (100%) create mode 100644 scanner/scanner.go delete mode 100644 service/helper_test.go delete mode 100644 service/holder_scanner_test.go delete mode 100644 service/holders_scanner.go delete mode 100644 service/tokenholders.go delete mode 100644 service/tokenholders_test.go diff --git a/api/api.go b/api/api.go index f0b6629b..c04c924e 100644 --- a/api/api.go +++ b/api/api.go @@ -7,8 +7,8 @@ import ( lru "github.com/hashicorp/golang-lru/v2" "github.com/vocdoni/census3/db" "github.com/vocdoni/census3/queue" - "github.com/vocdoni/census3/service/providers" - "github.com/vocdoni/census3/service/providers/web3" + "github.com/vocdoni/census3/scanner/providers" + "github.com/vocdoni/census3/scanner/providers/web3" "go.vocdoni.io/dvote/api/censusdb" storagelayer "go.vocdoni.io/dvote/data" "go.vocdoni.io/dvote/data/downloader" diff --git a/api/helpers.go b/api/helpers.go index 7b46a3a3..60e88b53 100644 --- a/api/helpers.go +++ b/api/helpers.go @@ -14,8 +14,8 @@ import ( "github.com/ethereum/go-ethereum/common" queries "github.com/vocdoni/census3/db/sqlc" "github.com/vocdoni/census3/lexer" - "github.com/vocdoni/census3/service/providers" - "github.com/vocdoni/census3/service/providers/web3" + "github.com/vocdoni/census3/scanner/providers" + "github.com/vocdoni/census3/scanner/providers/web3" "github.com/vocdoni/census3/strategyoperators" "go.vocdoni.io/dvote/api/censusdb" "go.vocdoni.io/dvote/censustree" diff --git a/api/holders.go b/api/holders.go index 057ae4fb..b062f5e1 100644 --- a/api/holders.go +++ b/api/holders.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common" queries "github.com/vocdoni/census3/db/sqlc" - "github.com/vocdoni/census3/service/providers/web3" + "github.com/vocdoni/census3/scanner/providers/web3" "go.vocdoni.io/dvote/httprouter" api "go.vocdoni.io/dvote/httprouter/apirest" "go.vocdoni.io/dvote/log" diff --git a/api/tokens.go b/api/tokens.go index 96eed583..84dbdbfe 100644 --- a/api/tokens.go +++ b/api/tokens.go @@ -15,8 +15,8 @@ import ( queries "github.com/vocdoni/census3/db/sqlc" "github.com/vocdoni/census3/internal" "github.com/vocdoni/census3/lexer" - "github.com/vocdoni/census3/service/providers" - "github.com/vocdoni/census3/service/providers/web3" + "github.com/vocdoni/census3/scanner/providers" + "github.com/vocdoni/census3/scanner/providers/web3" "go.vocdoni.io/dvote/httprouter" api "go.vocdoni.io/dvote/httprouter/apirest" "go.vocdoni.io/dvote/log" diff --git a/cmd/census3/main.go b/cmd/census3/main.go index 23e3ed40..1ddd445a 100644 --- a/cmd/census3/main.go +++ b/cmd/census3/main.go @@ -16,10 +16,10 @@ import ( "github.com/vocdoni/census3/api" "github.com/vocdoni/census3/db" "github.com/vocdoni/census3/internal" - "github.com/vocdoni/census3/service" - "github.com/vocdoni/census3/service/providers" - "github.com/vocdoni/census3/service/providers/poap" - "github.com/vocdoni/census3/service/providers/web3" + "github.com/vocdoni/census3/scanner" + "github.com/vocdoni/census3/scanner/providers" + "github.com/vocdoni/census3/scanner/providers/poap" + "github.com/vocdoni/census3/scanner/providers/web3" "go.vocdoni.io/dvote/log" ) @@ -134,11 +134,8 @@ func main() { providers.CONTRACT_TYPE_ERC20: erc20Provider, providers.CONTRACT_TYPE_POAP: poapProvider, } - // start the holder scanner with the database - hc, err := service.NewHoldersScanner(database, w3p, holderProviders, config.scannerCoolDown) - if err != nil { - log.Fatal(err) - } + // start the holder scanner with the database and the providers + hc := scanner.NewScanner(database, w3p, holderProviders, config.scannerCoolDown) // if the admin token is not defined, generate a random one if config.adminToken != "" { if _, err := uuid.Parse(config.adminToken); err != nil { @@ -176,6 +173,7 @@ func main() { log.Infof("waiting for routines to end gracefully...") // closing database go func() { + hc.Stop() if err := apiService.Stop(); err != nil { log.Fatal(err) } @@ -187,6 +185,7 @@ func main() { log.Fatal(err) } } + log.Infof("all routines ended") }() time.Sleep(5 * time.Second) os.Exit(0) diff --git a/service/const.go b/scanner/const.go similarity index 65% rename from service/const.go rename to scanner/const.go index c1d2a45e..75f46e1a 100644 --- a/service/const.go +++ b/scanner/const.go @@ -1,11 +1,14 @@ -package service +package scanner import "time" +const ( + SCAN_TIMEOUT = 5 * time.Minute + SAVE_TIMEOUT = time.Minute +) + const ( snapshotBlocks = 100000 // a snapshot and reset of the tree is performed every snapshotBlocks scanSleepTime = time.Second * 20 // time to sleep between scans scanSleepTimeOnceSync = time.Second * 120 // time to sleep between scans, once all the tokens are synced - // scanIterationDurationPerToken is the time the scanner will spend scanning each token, by iteration. - scanIterationDurationPerToken = 60 * time.Second ) diff --git a/service/providers/holders_provider.go b/scanner/providers/holders_provider.go similarity index 100% rename from service/providers/holders_provider.go rename to scanner/providers/holders_provider.go diff --git a/service/providers/poap/poap_provider.go b/scanner/providers/poap/poap_provider.go similarity index 99% rename from service/providers/poap/poap_provider.go rename to scanner/providers/poap/poap_provider.go index bf262fa9..7af4218a 100644 --- a/service/providers/poap/poap_provider.go +++ b/scanner/providers/poap/poap_provider.go @@ -11,7 +11,7 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" - "github.com/vocdoni/census3/service/providers" + "github.com/vocdoni/census3/scanner/providers" "go.vocdoni.io/dvote/log" ) diff --git a/service/providers/poap/poap_provider_test.go b/scanner/providers/poap/poap_provider_test.go similarity index 100% rename from service/providers/poap/poap_provider_test.go rename to scanner/providers/poap/poap_provider_test.go diff --git a/service/providers/types.go b/scanner/providers/types.go similarity index 100% rename from service/providers/types.go rename to scanner/providers/types.go diff --git a/service/providers/web3/const.go b/scanner/providers/web3/const.go similarity index 100% rename from service/providers/web3/const.go rename to scanner/providers/web3/const.go diff --git a/service/providers/web3/endpoint.go b/scanner/providers/web3/endpoint.go similarity index 100% rename from service/providers/web3/endpoint.go rename to scanner/providers/web3/endpoint.go diff --git a/service/providers/web3/endpoint_test.go b/scanner/providers/web3/endpoint_test.go similarity index 100% rename from service/providers/web3/endpoint_test.go rename to scanner/providers/web3/endpoint_test.go diff --git a/service/providers/web3/erc20_provider.go b/scanner/providers/web3/erc20_provider.go similarity index 99% rename from service/providers/web3/erc20_provider.go rename to scanner/providers/web3/erc20_provider.go index e1a887a7..e5ddd4a0 100644 --- a/service/providers/web3/erc20_provider.go +++ b/scanner/providers/web3/erc20_provider.go @@ -13,7 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" erc20 "github.com/vocdoni/census3/contracts/erc/erc20" - "github.com/vocdoni/census3/service/providers" + "github.com/vocdoni/census3/scanner/providers" "go.vocdoni.io/dvote/log" ) diff --git a/service/providers/web3/errors.go b/scanner/providers/web3/errors.go similarity index 100% rename from service/providers/web3/errors.go rename to scanner/providers/web3/errors.go diff --git a/service/providers/web3/helpers.go b/scanner/providers/web3/helpers.go similarity index 97% rename from service/providers/web3/helpers.go rename to scanner/providers/web3/helpers.go index 10f829bb..15881e86 100644 --- a/service/providers/web3/helpers.go +++ b/scanner/providers/web3/helpers.go @@ -8,7 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" - "github.com/vocdoni/census3/service/providers" + "github.com/vocdoni/census3/scanner/providers" ) func TokenTypeFromString(s string) uint64 { diff --git a/service/providers/web3/web3_provider.go b/scanner/providers/web3/web3_provider.go similarity index 100% rename from service/providers/web3/web3_provider.go rename to scanner/providers/web3/web3_provider.go diff --git a/scanner/scanner.go b/scanner/scanner.go new file mode 100644 index 00000000..2681d59b --- /dev/null +++ b/scanner/scanner.go @@ -0,0 +1,470 @@ +package scanner + +import ( + "context" + "database/sql" + "errors" + "fmt" + "math/big" + "sort" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/vocdoni/census3/db" + queries "github.com/vocdoni/census3/db/sqlc" + "github.com/vocdoni/census3/scanner/providers" + "github.com/vocdoni/census3/scanner/providers/web3" + "go.vocdoni.io/dvote/log" +) + +// ScannerToken includes the information of a token that the scanner needs to +// scan it. +type ScannerToken struct { + Address common.Address + ChainID uint64 + Type uint64 + ExternalID string + LastBlock uint64 + Ready bool + Synced bool +} + +// Scanner is the scanner that scans the tokens and saves the holders in the +// database. It has a list of tokens to scan and a list of providers to get the +// holders of the tokens. It has a cool down time between iterations to avoid +// overloading the providers. +type Scanner struct { + ctx context.Context + cancel context.CancelFunc + db *db.DB + networks web3.NetworkEndpoints + providers map[uint64]providers.HolderProvider + coolDown time.Duration + + tokens []*ScannerToken + tokensMtx sync.Mutex + waiter sync.WaitGroup +} + +// NewScanner returns a new scanner instance with the required parameters +// initialized. +func NewScanner(db *db.DB, networks web3.NetworkEndpoints, + providers map[uint64]providers.HolderProvider, coolDown time.Duration, +) *Scanner { + return &Scanner{ + db: db, + networks: networks, + providers: providers, + coolDown: coolDown, + tokens: []*ScannerToken{}, + tokensMtx: sync.Mutex{}, + waiter: sync.WaitGroup{}, + } +} + +// Start starts the scanner. It starts a loop that scans the tokens in the +// database and saves the holders in the database. It stops when the context is +// cancelled. +func (s *Scanner) Start(ctx context.Context) { + s.ctx, s.cancel = context.WithCancel(ctx) + itCounter := 0 + for { + select { + case <-ctx.Done(): + return + default: + itCounter++ + startTime := time.Now() + tokens, err := s.TokensToScan(ctx) + if err != nil { + log.Error(err) + continue + } + atSyncGlobal := true + for _, token := range tokens { + holders, lastBlock, synced, err := s.ScanHolders(ctx, token) + if err != nil { + log.Error(err) + continue + } + if !synced { + atSyncGlobal = false + } + if len(holders) > 0 { + s.waiter.Add(1) + go func(t *ScannerToken, h map[common.Address]*big.Int, lb uint64, sy bool) { + defer s.waiter.Done() + if err = s.SaveHolders(ctx, t, h, lb, sy); err != nil { + log.Error(err) + } + }(token, holders, lastBlock, synced) + } + } + log.Infow("scan iteration finished", + "iteration", itCounter, + "duration", time.Since(startTime).Seconds(), + "atSync", atSyncGlobal) + if atSyncGlobal { + time.Sleep(s.coolDown) + } else { + time.Sleep(scanSleepTime) + } + } + } +} + +// Stop stops the scanner. It cancels the context and waits for the scanner to +// finish. +func (s *Scanner) Stop() { + s.cancel() + s.waiter.Wait() +} + +// TokensToScan returns the tokens that the scanner has to scan. It returns the +// the tokens to scan from the database in the following order: +// 1. The tokens that were created in the last 60 minutes and are not synced. +// 2. The rest of no synced tokens, sorted by the difference between their +// block number and the last block number of their chain. +// 3. The tokens that were synced in previous iterations. +func (s *Scanner) TokensToScan(ctx context.Context) ([]*ScannerToken, error) { + internalCtx, cancel := context.WithTimeout(ctx, SCAN_TIMEOUT) + defer cancel() + // create a tx to use it in the following queries + tx, err := s.db.RW.BeginTx(internalCtx, nil) + if err != nil { + return nil, err + } + defer func() { + if err := tx.Rollback(); err != nil && !errors.Is(sql.ErrTxDone, err) { + log.Error(err) + return + } + }() + qtx := s.db.QueriesRW.WithTx(tx) + + tokens := []*ScannerToken{} + // get last created tokens from the database to scan them first + lastNotSyncedTokens, err := qtx.ListLastNoSyncedTokens(ctx) + if err != nil && !errors.Is(sql.ErrNoRows, err) { + return nil, err + } + // parse last not synced token addresses + for _, token := range lastNotSyncedTokens { + lastBlock := uint64(token.CreationBlock) + if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil { + lastBlock = blockNumber + } + tokens = append(tokens, &ScannerToken{ + Address: common.BytesToAddress(token.ID), + ChainID: token.ChainID, + Type: token.TypeID, + ExternalID: token.ExternalID, + LastBlock: lastBlock, + Ready: token.CreationBlock > 0, + Synced: token.Synced, + }) + } + // get old tokens from the database + oldNotSyncedTokens, err := qtx.ListOldNoSyncedTokens(ctx) + if err != nil && !errors.Is(sql.ErrNoRows, err) { + return nil, err + } + // get the current block number of every chain + currentBlockNumbers, err := s.networks.CurrentBlockNumbers(ctx) + if err != nil { + return nil, err + } + // sort old not synced tokens by nearest to be synced, that is, the tokens + // that have the minimum difference between the current block of its chain + // and the last block scanned by the scanner (retrieved from the database + // as LastBlock) + sort.Slice(oldNotSyncedTokens, func(i, j int) bool { + iLastBlock := uint64(oldNotSyncedTokens[i].CreationBlock) + if oldNotSyncedTokens[i].LastBlock != nil { + iLastBlock = uint64(oldNotSyncedTokens[i].LastBlock.(int64)) + } + jLastBlock := uint64(oldNotSyncedTokens[j].CreationBlock) + if oldNotSyncedTokens[j].LastBlock != nil { + jLastBlock = uint64(oldNotSyncedTokens[j].LastBlock.(int64)) + } + iBlocksReamining := currentBlockNumbers[oldNotSyncedTokens[i].ChainID] - uint64(iLastBlock) + jBlocksReamining := currentBlockNumbers[oldNotSyncedTokens[j].ChainID] - uint64(jLastBlock) + return iBlocksReamining < jBlocksReamining + }) + // parse old not synced token addresses + for _, token := range oldNotSyncedTokens { + lastBlock := uint64(token.CreationBlock) + if token.LastBlock != nil { + lastBlock = uint64(token.LastBlock.(int64)) + } + tokens = append(tokens, &ScannerToken{ + Address: common.BytesToAddress(token.ID), + ChainID: token.ChainID, + Type: token.TypeID, + ExternalID: token.ExternalID, + LastBlock: lastBlock, + Ready: token.CreationBlock > 0, + Synced: token.Synced, + }) + } + // get last created tokens from the database to scan them first + syncedTokens, err := qtx.ListSyncedTokens(ctx) + if err != nil && !errors.Is(sql.ErrNoRows, err) { + return nil, err + } + for _, token := range syncedTokens { + lastBlock := uint64(token.CreationBlock) + if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil { + lastBlock = blockNumber + } + s.tokens = append(s.tokens, &ScannerToken{ + Address: common.BytesToAddress(token.ID), + ChainID: token.ChainID, + Type: token.TypeID, + ExternalID: token.ExternalID, + LastBlock: lastBlock, + Ready: token.CreationBlock > 0, + Synced: token.Synced, + }) + } + // close the database tx and commit it + if err := tx.Commit(); err != nil { + return nil, err + } + // update the tokens to scan in the scanner and return them + s.tokensMtx.Lock() + s.tokens = tokens + s.tokensMtx.Unlock() + return tokens, nil +} + +// ScanHolders scans the holders of the given token. It get the current holders +// from the database, set them into the provider and get the new ones. It +// returns the new holders, the last block scanned and if the token is synced +// after the scan. +func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) (map[common.Address]*big.Int, uint64, bool, error) { + log.Infow("scanning holders", + "address", token.Address.Hex(), + "chainID", token.ChainID, + "externalID", token.ExternalID) + internalCtx, cancel := context.WithTimeout(ctx, SCAN_TIMEOUT) + defer cancel() + // get the correct token holder for the current token + provider, exists := s.providers[token.ChainID] + if !exists { + return nil, token.LastBlock, token.Synced, fmt.Errorf("no provider for chain %d", token.ChainID) + } + // create a tx to use it in the following queries + tx, err := s.db.RW.BeginTx(internalCtx, nil) + if err != nil { + return nil, token.LastBlock, token.Synced, err + } + defer func() { + if err := tx.Rollback(); err != nil && !errors.Is(sql.ErrTxDone, err) { + log.Error(err) + } + }() + qtx := s.db.QueriesRW.WithTx(tx) + // if the provider is not an external one, instance the current token + if !provider.IsExternal() { + if err := provider.SetRef(web3.Web3ProviderRef{ + HexAddress: token.Address.Hex(), + ChainID: token.ChainID, + }); err != nil { + return nil, token.LastBlock, token.Synced, err + } + // if the token is not ready yet (its creation block has not been + // calculated yet), calculate it, update the token information and + // return + if !token.Ready { + creationBlock, err := provider.CreationBlock(internalCtx, []byte(token.ExternalID)) + if err != nil { + return nil, token.LastBlock, token.Synced, err + } + _, err = qtx.UpdateTokenCreationBlock(internalCtx, queries.UpdateTokenCreationBlockParams{ + ID: token.Address.Bytes(), + ChainID: token.ChainID, + ExternalID: token.ExternalID, + CreationBlock: int64(creationBlock), + }) + if err != nil { + return nil, token.LastBlock, token.Synced, err + } + // close the database tx and commit it + return nil, token.LastBlock, token.Synced, tx.Commit() + } + } + // get the current token holders from the database + results, err := qtx.TokenHoldersByTokenIDAndChainIDAndExternalID(internalCtx, + queries.TokenHoldersByTokenIDAndChainIDAndExternalIDParams{ + TokenID: token.Address.Bytes(), + ChainID: token.ChainID, + ExternalID: token.ExternalID, + }) + if err != nil { + return nil, token.LastBlock, token.Synced, err + } + currentHolders := map[common.Address]*big.Int{} + for _, result := range results { + currentHolders[common.BytesToAddress(result.ID)] = big.NewInt(0).SetBytes([]byte(result.Balance)) + } + // close the database tx and commit it + if err := tx.Commit(); err != nil { + return nil, token.LastBlock, token.Synced, err + } + // set the current holders into the provider and get the new ones + if err := provider.SetLastBalances(ctx, []byte(token.ExternalID), currentHolders, token.LastBlock); err != nil { + return nil, token.LastBlock, token.Synced, err + } + return provider.HoldersBalances(ctx, []byte(token.ExternalID), token.LastBlock) +} + +// SaveHolders saves the given holders in the database. It updates the token +// synced status if it is different from the received one. Then, it creates, +// updates or deletes the token holders in the database depending on the +// calculated balance. +func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, + holders map[common.Address]*big.Int, lastBlock uint64, synced bool) error { + log.Debugw("saving token holders", + "token", token.Address.Hex(), + "chainID", token.ChainID, + "externalID", token.ExternalID, + "block", lastBlock, + "holders", len(holders)) + + s.tokensMtx.Lock() + for i, t := range s.tokens { + if t.Address == token.Address && t.ChainID == token.ChainID && t.ExternalID == token.ExternalID { + s.tokens[i].LastBlock = lastBlock + s.tokens[i].Synced = synced + break + } + } + s.tokensMtx.Unlock() + + internalCtx, cancel := context.WithTimeout(ctx, SAVE_TIMEOUT) + defer cancel() + // create a tx to use it in the following queries + tx, err := s.db.RW.BeginTx(internalCtx, nil) + if err != nil { + return err + } + defer func() { + if err := tx.Rollback(); err != nil && !errors.Is(sql.ErrTxDone, err) { + log.Error(err) + } + }() + qtx := s.db.QueriesRW.WithTx(tx) + // get the current token information from the database + tokenInfo, err := qtx.TokenByIDAndChainIDAndExternalID(internalCtx, + queries.TokenByIDAndChainIDAndExternalIDParams{ + ID: token.Address.Bytes(), + ChainID: token.ChainID, + ExternalID: token.ExternalID, + }) + if err != nil { + return err + } + // if the token synced status is not the same that the received one, update + // it in the database + if tokenInfo.Synced != synced { + _, err = qtx.UpdateTokenStatus(internalCtx, queries.UpdateTokenStatusParams{ + ID: token.Address.Bytes(), + ChainID: token.ChainID, + ExternalID: token.ExternalID, + Synced: synced, + }) + if err != nil { + return err + } + if synced { + log.Infow("token synced", + "token", token.Address.Hex(), + "chainID", token.ChainID, + "externalID", token.ExternalID) + } + } + created, updated, deleted := 0, 0, 0 + for addr, balance := range holders { + switch balance.Cmp(big.NewInt(0)) { + case -1: + // if the calculated balance is negative,try todelete the token holder + if _, err := qtx.DeleteTokenHolder(ctx, queries.DeleteTokenHolderParams{ + TokenID: token.Address.Bytes(), + ChainID: token.ChainID, + ExternalID: token.ExternalID, + HolderID: addr.Bytes(), + }); err != nil { + return fmt.Errorf("error deleting token holder: %w", err) + } + deleted++ + case 1: + // get the current token holder from the database + currentTokenHolder, err := qtx.TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID(ctx, + queries.TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDParams{ + TokenID: token.Address.Bytes(), + ChainID: token.ChainID, + ExternalID: token.ExternalID, + HolderID: addr.Bytes(), + }) + if err != nil { + if !errors.Is(sql.ErrNoRows, err) { + return err + } + // if the token holder not exists, create it + _, err = qtx.CreateTokenHolder(ctx, queries.CreateTokenHolderParams{ + TokenID: token.Address.Bytes(), + ChainID: token.ChainID, + ExternalID: token.ExternalID, + HolderID: addr.Bytes(), + BlockID: lastBlock, + Balance: balance.String(), + }) + if err != nil { + return err + } + created++ + continue + } + // parse the current token holder balance and compare it with the + // calculated one, if they are the same, continue + currentBalance, ok := new(big.Int).SetString(currentTokenHolder.Balance, 10) + if !ok { + return fmt.Errorf("error parsing current token holder balance") + } + if currentBalance.Cmp(balance) == 0 { + continue + } + // if the calculated balance is not 0 or less and it is different + // from the current one, update it in the database + _, err = qtx.UpdateTokenHolderBalance(ctx, queries.UpdateTokenHolderBalanceParams{ + TokenID: token.Address.Bytes(), + ChainID: token.ChainID, + ExternalID: token.ExternalID, + HolderID: addr.Bytes(), + BlockID: currentTokenHolder.BlockID, + NewBlockID: lastBlock, + Balance: balance.String(), + }) + if err != nil { + return fmt.Errorf("error updating token holder: %w", err) + } + updated++ + } + } + // close the database tx and commit it + if err := tx.Commit(); err != nil { + return err + } + log.Debugw("token holders saved", + "token", token.Address.Hex(), + "chainID", token.ChainID, + "externalID", token.ExternalID, + "block", token.LastBlock, + "synced", token.Synced, + "created", created, + "updated", updated, + "deleted", deleted) + return nil +} diff --git a/service/helper_test.go b/service/helper_test.go deleted file mode 100644 index 159200a2..00000000 --- a/service/helper_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package service - -import ( - "fmt" - "math/big" - "os" - "testing" - - "github.com/ethereum/go-ethereum/common" - qt "github.com/frankban/quicktest" - "github.com/vocdoni/census3/db" - "github.com/vocdoni/census3/db/annotations" - queries "github.com/vocdoni/census3/db/sqlc" - "github.com/vocdoni/census3/service/providers" -) - -var ( - MonkeysAddress = common.HexToAddress("0xF530280176385AF31177D78BbFD5eA3f6D07488A") - MonkeysType = providers.CONTRACT_TYPE_ERC20 - MonkeysCreationBlock = uint64(8901659) - MonkeysSymbol = "MON" - MonkeysName = "Monkeys" - MonkeysDecimals = uint64(18) - MonkeysTotalSupply, _ = new(big.Int).SetString("82000000000000000000", 10) - MonkeysHolders = map[common.Address]*big.Int{ - common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012"): new(big.Int).SetUint64(16000000000000000000), - common.HexToAddress("0x38d2BC91B89928f78cBaB3e4b1949e28787eC7a3"): new(big.Int).SetUint64(13000000000000000000), - common.HexToAddress("0xF752B527E2ABA395D1Ba4C0dE9C147B763dDA1f4"): new(big.Int).SetUint64(12000000000000000000), - common.HexToAddress("0xe1308a8d0291849bfFb200Be582cB6347FBE90D9"): new(big.Int).SetUint64(9000000000000000000), - common.HexToAddress("0xdeb8699659bE5d41a0e57E179d6cB42E00B9200C"): new(big.Int).SetUint64(7000000000000000000), - common.HexToAddress("0xB1F05B11Ba3d892EdD00f2e7689779E2B8841827"): new(big.Int).SetUint64(5000000000000000000), - common.HexToAddress("0xF3C456FAAa70fea307A073C3DA9572413c77f58B"): new(big.Int).SetUint64(6000000000000000000), - common.HexToAddress("0x45D3a03E8302de659e7Ea7400C4cfe9CAED8c723"): new(big.Int).SetUint64(6000000000000000000), - common.HexToAddress("0x313c7f7126486fFefCaa9FEA92D968cbf891b80c"): new(big.Int).SetUint64(3000000000000000000), - common.HexToAddress("0x1893eD78480267D1854373A99Cee8dE2E08d430F"): new(big.Int).SetUint64(2000000000000000000), - common.HexToAddress("0xa2E4D94c5923A8dd99c5792A7B0436474c54e1E1"): new(big.Int).SetUint64(2000000000000000000), - common.HexToAddress("0x2a4636A5a1138e35F7f93e81FA56d3c970BC6777"): new(big.Int).SetUint64(1000000000000000000), - } - NoEventID = new(big.Int).SetBytes([]byte{}) -) - -type TestDB struct { - dir string - db *db.DB -} - -func StartTestDB(t *testing.T) *TestDB { - c := qt.New(t) - - dir := t.TempDir() - db, err := db.Init(dir) - c.Assert(err, qt.IsNil) - return &TestDB{dir, db} -} - -func (testdb *TestDB) Close(t *testing.T) { - c := qt.New(t) - c.Assert(testdb.db.RW.Close(), qt.IsNil) - c.Assert(testdb.db.RO.Close(), qt.IsNil) - c.Assert(os.RemoveAll(testdb.dir), qt.IsNil) -} - -func testTokenParams(id, name, symbol string, creationBlock, decimals, typeID uint64, - totalSupply int64, synced bool, chainID uint64, externalID string, -) queries.CreateTokenParams { - return queries.CreateTokenParams{ - ID: common.HexToAddress(id).Bytes(), - Name: name, - Symbol: symbol, - Decimals: decimals, - TotalSupply: annotations.BigInt(fmt.Sprint(totalSupply)), - CreationBlock: int64(creationBlock), - TypeID: typeID, - Synced: synced, - ChainID: chainID, - ExternalID: externalID, - } -} diff --git a/service/holder_scanner_test.go b/service/holder_scanner_test.go deleted file mode 100644 index dd314f8e..00000000 --- a/service/holder_scanner_test.go +++ /dev/null @@ -1,235 +0,0 @@ -package service - -import ( - "context" - "database/sql" - "math/big" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - qt "github.com/frankban/quicktest" - queries "github.com/vocdoni/census3/db/sqlc" - "github.com/vocdoni/census3/service/providers" - "github.com/vocdoni/census3/service/providers/web3" -) - -var ( - web3endpoint, _ = web3.TestNetworkEndpoint() - web3Endpoints = map[uint64]*web3.NetworkEndpoint{ - web3endpoint.ChainID: web3endpoint, - } - holdersProviders = map[uint64]providers.HolderProvider{ - MonkeysType: new(web3.ERC20HolderProvider), - } -) - -func init() { - if err := holdersProviders[MonkeysType].Init(web3.Web3ProviderConfig{ - Endpoints: web3Endpoints, - }); err != nil { - panic(err) - } -} - -func TestNewHolderScanner(t *testing.T) { - c := qt.New(t) - - testdb := StartTestDB(t) - defer testdb.Close(t) - - hs, err := NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) - c.Assert(err, qt.IsNil) - c.Assert(hs.lastBlock, qt.Equals, uint64(0)) - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - _, err = testdb.db.QueriesRW.CreateBlock(ctx, queries.CreateBlockParams{ - ID: 1000, - Timestamp: "test", - RootHash: []byte("test"), - }) - c.Assert(err, qt.IsNil) - - hs, err = NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) - c.Assert(err, qt.IsNil) - c.Assert(hs.lastBlock, qt.Equals, uint64(1000)) - - _, err = NewHoldersScanner(nil, web3Endpoints, holdersProviders, 20) - c.Assert(err, qt.IsNotNil) -} - -func TestHolderScannerStart(t *testing.T) { - c := qt.New(t) - twg := sync.WaitGroup{} - - ctx, cancel := context.WithCancel(context.Background()) - testdb := StartTestDB(t) - defer testdb.Close(t) - - twg.Add(1) - hs, err := NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) - c.Assert(err, qt.IsNil) - go func() { - hs.Start(ctx) - twg.Done() - }() - - cancel() - twg.Wait() -} - -func Test_getTokensToScan(t *testing.T) { - c := qt.New(t) - - testdb := StartTestDB(t) - defer testdb.Close(t) - - hs, err := NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) - c.Assert(err, qt.IsNil) - c.Assert(hs.getTokensToScan(), qt.IsNil) - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - _, err = testdb.db.QueriesRW.CreateToken(ctx, testTokenParams("0x1", "test0", - "test0", 0, MonkeysDecimals, uint64(providers.CONTRACT_TYPE_ERC20), - MonkeysTotalSupply.Int64(), false, 5, "")) - c.Assert(err, qt.IsNil) - - err = hs.getTokensToScan() - c.Assert(err, qt.IsNil) - c.Assert(hs.tokens[0].IsReady(), qt.IsFalse) - c.Assert(hs.tokens[0].Address().String(), qt.Equals, common.HexToAddress("0x1").String()) - - _, err = testdb.db.QueriesRW.CreateToken(ctx, testTokenParams("0x2", "test2", - "test3", 10, MonkeysDecimals, uint64(providers.CONTRACT_TYPE_ERC20), - MonkeysTotalSupply.Int64(), false, 5, "")) - c.Assert(err, qt.IsNil) - - err = hs.getTokensToScan() - c.Assert(err, qt.IsNil) - c.Assert(hs.calcTokenCreationBlock(ctx, 1), qt.IsNil) - c.Assert(hs.tokens[1].IsReady(), qt.IsTrue) - c.Assert(hs.tokens[1].Address().String(), qt.Equals, common.HexToAddress("0x2").String()) -} - -func Test_saveHolders(t *testing.T) { - c := qt.New(t) - - testdb := StartTestDB(t) - defer testdb.Close(t) - - hs, err := NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) - c.Assert(err, qt.IsNil) - - th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - // no registered token - c.Assert(hs.saveHolders(th), qt.ErrorIs, ErrTokenNotExists) - _, err = testdb.db.QueriesRW.CreateToken(context.Background(), testTokenParams( - MonkeysAddress.String(), MonkeysName, MonkeysSymbol, MonkeysCreationBlock, - MonkeysDecimals, uint64(providers.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) - c.Assert(err, qt.IsNil) - // check no new holders - c.Assert(hs.saveHolders(th), qt.IsNil) - // mock holder - holderAddr := common.HexToAddress("0x1") - holderBalance := new(big.Int).SetInt64(12) - th.Append(holderAddr, holderBalance) - th.BlockDone(MonkeysCreationBlock) - // check web3 - c.Assert(hs.saveHolders(th), qt.IsNil) - // check new holders - res, err := testdb.db.QueriesRO.TokenHolderByTokenIDAndHolderID(context.Background(), - queries.TokenHolderByTokenIDAndHolderIDParams{ - TokenID: MonkeysAddress.Bytes(), - HolderID: holderAddr.Bytes(), - ChainID: th.ChainID, - }) - c.Assert(err, qt.IsNil) - c.Assert(res.Balance, qt.ContentEquals, holderBalance.String()) - // check update holders - th.Append(holderAddr, holderBalance) - c.Assert(hs.saveHolders(th), qt.IsNil) - res, err = testdb.db.QueriesRO.TokenHolderByTokenIDAndHolderID(context.Background(), - queries.TokenHolderByTokenIDAndHolderIDParams{ - TokenID: MonkeysAddress.Bytes(), - HolderID: holderAddr.Bytes(), - ChainID: th.ChainID, - }) - c.Assert(err, qt.IsNil) - resBalance, ok := new(big.Int).SetString(res.Balance, 10) - c.Assert(ok, qt.IsTrue) - c.Assert(resBalance.String(), qt.Equals, "12") - // check delete holders - th.Append(holderAddr, big.NewInt(-24)) - c.Assert(hs.saveHolders(th), qt.IsNil) - _, err = testdb.db.QueriesRO.TokenHolderByTokenIDAndHolderID(context.Background(), - queries.TokenHolderByTokenIDAndHolderIDParams{ - TokenID: MonkeysAddress.Bytes(), - HolderID: holderAddr.Bytes(), - }) - c.Assert(err, qt.ErrorIs, sql.ErrNoRows) -} - -func Test_scanHolders(t *testing.T) { - c := qt.New(t) - - testdb := StartTestDB(t) - defer testdb.Close(t) - - hs, err := NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) - c.Assert(err, qt.IsNil) - - // token does not exists - ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - _, err = hs.scanHolders(ctx1, MonkeysAddress, 5, []byte{}) - c.Assert(err, qt.IsNotNil) - - _, err = testdb.db.QueriesRW.CreateToken(context.Background(), testTokenParams( - MonkeysAddress.String(), MonkeysName, MonkeysSymbol, MonkeysCreationBlock, - MonkeysDecimals, uint64(providers.CONTRACT_TYPE_ERC20), 10, false, 5, "")) - c.Assert(err, qt.IsNil) - // token exists and the scanner gets the holders - ctx2, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - _, err = hs.scanHolders(ctx2, MonkeysAddress, 5, []byte{}) - c.Assert(err, qt.IsNil) - - res, err := testdb.db.QueriesRW.TokenHoldersByTokenID(context.Background(), MonkeysAddress.Bytes()) - c.Assert(err, qt.IsNil) - for _, holder := range res { - balance, ok := MonkeysHolders[common.BytesToAddress(holder.ID)] - c.Assert(ok, qt.IsTrue) - currentBalance, ok := new(big.Int).SetString(holder.Balance, 10) - c.Assert(ok, qt.IsTrue) - c.Assert(currentBalance.String(), qt.ContentEquals, balance.String()) - } -} - -func Test_calcTokenCreationBlock(t *testing.T) { - c := qt.New(t) - - testdb := StartTestDB(t) - defer testdb.Close(t) - - hs, err := NewHoldersScanner(testdb.db, web3Endpoints, holdersProviders, 20) - hs.tokens = append(hs.tokens, new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, 0, 5, "")) - c.Assert(err, qt.IsNil) - c.Assert(hs.calcTokenCreationBlock(context.Background(), 0), qt.IsNotNil) - - _, err = testdb.db.QueriesRW.CreateToken(context.Background(), testTokenParams( - MonkeysAddress.String(), MonkeysName, MonkeysSymbol, MonkeysCreationBlock, - MonkeysDecimals, uint64(providers.CONTRACT_TYPE_ERC20), MonkeysTotalSupply.Int64(), false, 5, "")) - c.Assert(err, qt.IsNil) - - c.Assert(hs.calcTokenCreationBlock(context.Background(), 0), qt.IsNil) - token, err := testdb.db.QueriesRO.TokenByIDAndChainID(context.Background(), - queries.TokenByIDAndChainIDParams{ - ID: MonkeysAddress.Bytes(), - ChainID: 5, - }) - c.Assert(err, qt.IsNil) - c.Assert(uint64(token.CreationBlock), qt.Equals, MonkeysCreationBlock) -} diff --git a/service/holders_scanner.go b/service/holders_scanner.go deleted file mode 100644 index 8a53eb47..00000000 --- a/service/holders_scanner.go +++ /dev/null @@ -1,577 +0,0 @@ -package service - -import ( - "bytes" - "context" - "database/sql" - "errors" - "fmt" - "math/big" - "sort" - "strings" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common" - _ "github.com/mattn/go-sqlite3" - - "github.com/vocdoni/census3/db" - queries "github.com/vocdoni/census3/db/sqlc" - "github.com/vocdoni/census3/service/providers" - "github.com/vocdoni/census3/service/providers/web3" - "go.vocdoni.io/dvote/log" -) - -var ( - ErrNoDB = fmt.Errorf("no database instance provided") - ErrHalted = fmt.Errorf("scanner loop halted") - ErrTokenNotExists = fmt.Errorf("token does not exists") -) - -// HoldersScanner struct contains the needed parameters to scan the holders of -// the tokens stored on the database (located on 'dataDir/dbFilename'). It -// keeps the database updated scanning the network using the web3 endpoint. -type HoldersScanner struct { - w3p web3.NetworkEndpoints - tokens []*TokenHolders - mutex sync.RWMutex - db *db.DB - lastBlock uint64 - holderProviders map[uint64]providers.HolderProvider - coolDown time.Duration -} - -// NewHoldersScanner function creates a new HolderScanner using the dataDir path -// and the web3 endpoint URI provided. It sets up a sqlite3 database instance -// and gets the number of last block scanned from it. -func NewHoldersScanner(db *db.DB, w3p web3.NetworkEndpoints, - holderProviders map[uint64]providers.HolderProvider, coolDown time.Duration, -) (*HoldersScanner, error) { - if db == nil { - return nil, ErrNoDB - } - // create an empty scanner - s := HoldersScanner{ - w3p: w3p, - tokens: []*TokenHolders{}, - db: db, - holderProviders: holderProviders, - coolDown: coolDown, - } - // get latest analyzed block - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - lastBlock, err := s.db.QueriesRO.LastBlock(ctx) - if err == nil { - s.lastBlock = lastBlock - } - return &s, nil -} - -// Start function initialises the given scanner until the provided context is -// canceled. It first gets the addresses of the tokens to scan and their current -// token state. It then starts scanning, keeping these lists updated and -// synchronised with the database instance. -func (s *HoldersScanner) Start(ctx context.Context) { - // monitor for new tokens added and update every token holders - itCounter := uint64(0) - for { - select { - case <-ctx.Done(): - log.Info(ErrHalted) - return - default: - itCounter++ - startTime := time.Now() - // get updated list of tokens - if err := s.getTokensToScan(); err != nil { - log.Error(err) - continue - } - // scan for new holders of every token - atSyncGlobal := true - for index, data := range s.tokens { - if !data.IsReady() { - if err := s.calcTokenCreationBlock(ctx, index); err != nil { - log.Error(err) - continue - } - } - atSync, err := s.scanHolders(ctx, data.Address(), data.ChainID, []byte(data.ExternalID)) - if err != nil { - log.Error(err) - continue - } - if !atSync { - atSyncGlobal = false - } - } - log.Infow("scan iteration finished", - "iteration", itCounter, - "duration", time.Since(startTime).Seconds(), - "atSync", atSyncGlobal) - if atSyncGlobal { - time.Sleep(s.coolDown) - } else { - time.Sleep(scanSleepTime) - } - } - } -} - -func (s *HoldersScanner) getProvider(tokenType uint64) (providers.HolderProvider, bool) { - if provider, exists := s.holderProviders[tokenType]; exists { - return provider, true - } - return nil, false -} - -// getTokensToScan function gets the information of the current tokens to scan, -// including its addresses from the database. If the current database instance -// does not contain any token, it returns nil addresses without error. -// This behaviour helps to deal with this particular case. It also filters the -// tokens to retunr only the ones that are ready to be scanned, which means that -// the token creation block is already calculated. -func (s *HoldersScanner) getTokensToScan() error { - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - tx, err := s.db.RO.BeginTx(ctx, nil) - if err != nil { - return err - } - defer func() { - if err := tx.Rollback(); err != nil && !errors.Is(sql.ErrTxDone, err) { - log.Errorf("error rolling back transaction when scanner get token addresses: %v", err) - } - }() - qtx := s.db.QueriesRW.WithTx(tx) - s.tokens = []*TokenHolders{} - // get last created tokens from the database to scan them first - lastNotSyncedTokens, err := qtx.ListLastNoSyncedTokens(ctx) - if err != nil && !errors.Is(sql.ErrNoRows, err) { - return err - } - // parse last not synced token addresses - for _, token := range lastNotSyncedTokens { - lastBlock := uint64(0) - if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil { - lastBlock = blockNumber - } - s.tokens = append(s.tokens, new(TokenHolders).Init( - common.BytesToAddress(token.ID), token.TypeID, - lastBlock, token.ChainID, token.ExternalID)) - } - // get old tokens from the database - oldNotSyncedTokens, err := qtx.ListOldNoSyncedTokens(ctx) - if err != nil && !errors.Is(sql.ErrNoRows, err) { - return err - } - // get the current block number of every chain - currentBlockNumbers, err := s.w3p.CurrentBlockNumbers(ctx) - if err != nil { - return err - } - // sort old not synced tokens by nearest to be synced, that is, the tokens - // that have the minimum difference between the current block of its chain - // and the last block scanned by the scanner (retrieved from the database - // as LastBlock) - sort.Slice(oldNotSyncedTokens, func(i, j int) bool { - iLastBlock := uint64(0) - if oldNotSyncedTokens[i].LastBlock != nil { - iLastBlock = uint64(oldNotSyncedTokens[i].LastBlock.(int64)) - } - jLastBlock := uint64(0) - if oldNotSyncedTokens[j].LastBlock != nil { - jLastBlock = uint64(oldNotSyncedTokens[j].LastBlock.(int64)) - } - iBlocksReamining := currentBlockNumbers[oldNotSyncedTokens[i].ChainID] - uint64(iLastBlock) - jBlocksReamining := currentBlockNumbers[oldNotSyncedTokens[j].ChainID] - uint64(jLastBlock) - return iBlocksReamining < jBlocksReamining - }) - // parse old not synced token addresses - for _, token := range oldNotSyncedTokens { - lastBlock := uint64(0) - if token.LastBlock != nil { - lastBlock = uint64(token.LastBlock.(int64)) - } - s.tokens = append(s.tokens, new(TokenHolders).Init( - common.BytesToAddress(token.ID), token.TypeID, - lastBlock, token.ChainID, token.ExternalID)) - } - // get last created tokens from the database to scan them first - syncedTokens, err := qtx.ListSyncedTokens(ctx) - if err != nil && !errors.Is(sql.ErrNoRows, err) { - return err - } - for _, token := range syncedTokens { - lastBlock := uint64(0) - if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil { - lastBlock = blockNumber - } - s.tokens = append(s.tokens, new(TokenHolders).Init( - common.BytesToAddress(token.ID), token.TypeID, - lastBlock, token.ChainID, token.ExternalID)) - } - return nil -} - -// saveHolders function updates the current HoldersScanner database with the -// TokenHolders state provided. Updates the holders for associated token and -// the blocks scanned. To do this, it requires the root hash and the timestampt -// of the given TokenHolders state block. -func (s *HoldersScanner) saveHolders(th *TokenHolders) error { - log.Debugw("saving token holders", - "token", th.Address(), - "chainID", th.ChainID, - "externalID", th.ExternalID, - "block", th.LastBlock(), - "holders", len(th.Holders())) - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - // begin a transaction for group sql queries - tx, err := s.db.RW.BeginTx(ctx, nil) - if err != nil { - return err - } - defer func() { - _ = tx.Rollback() - }() - qtx := s.db.QueriesRW.WithTx(tx) - if exists, err := qtx.ExistsTokenByChainIDAndExternalID(ctx, queries.ExistsTokenByChainIDAndExternalIDParams{ - ID: th.Address().Bytes(), - ChainID: th.ChainID, - ExternalID: th.ExternalID, - }); err != nil { - return fmt.Errorf("error checking if token exists: %w", err) - } else if !exists { - return ErrTokenNotExists - } - provider, exists := s.getProvider(th.Type()) - if !exists { - return fmt.Errorf("token type not supported") - } - if !provider.IsExternal() { - // init web3 contract state - if err := provider.SetRef(web3.Web3ProviderRef{ - HexAddress: th.Address().Hex(), - ChainID: th.ChainID, - }); err != nil { - return err - } - } - if latest, err := provider.LatestBlockNumber(ctx, []byte(th.ExternalID)); err == nil && th.LastBlock() >= latest { - th.Synced() - } - _, err = qtx.UpdateTokenStatus(ctx, queries.UpdateTokenStatusParams{ - Synced: th.IsSynced(), - ID: th.Address().Bytes(), - ChainID: th.ChainID, - ExternalID: th.ExternalID, - }) - if err != nil { - return fmt.Errorf("error updating token: %w", err) - } - // if not token holders received, skip - if len(th.Holders()) == 0 { - log.Debug("no holders to save. skip scanning and saving...") - // save btw to update if token is synced - if err := tx.Commit(); err != nil { - return err - } - return nil - } - // get the block timestamp and root hash from the holder provider, it does - // not matter if it is an external provider or a web3 one - var timestamp string - var rootHash []byte - // get current block number timestamp and root hash, required parameters to - // create a new block in the database - timestamp, err = provider.BlockTimestamp(ctx, th.LastBlock()) - if err != nil { - return err - } - rootHash, err = provider.BlockRootHash(ctx, th.LastBlock()) - if err != nil { - return err - } - // if the current HoldersScanner last block not exists in the database, - // create it - if _, err := qtx.BlockByID(ctx, th.LastBlock()); err != nil { - if !errors.Is(sql.ErrNoRows, err) { - return err - } - _, err = qtx.CreateBlock(ctx, queries.CreateBlockParams{ - ID: th.LastBlock(), - Timestamp: timestamp, - RootHash: rootHash, - }) - if err != nil { - return err - } - } - // iterate over given holders - // - if the holder not exists, create it - // - if the holder already exists, calculate the new balance with the - // current balance - // - if the calculated balance is 0 delete it - // - if the calculated balance is not 0, update it - created, updated, deleted := 0, 0, 0 - for holder, balance := range th.Holders() { - currentTokenHolder, err := qtx.TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID(ctx, - queries.TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDParams{ - TokenID: th.Address().Bytes(), - HolderID: holder.Bytes(), - ChainID: th.ChainID, - ExternalID: th.ExternalID, - }) - if err != nil { - // return the error if fails and the error is not 'no rows' err - if !errors.Is(sql.ErrNoRows, err) { - return err - } - // if the token holder not exists and the balance is 0 or less, skip - // it - if balance.Cmp(big.NewInt(0)) != 1 { - continue - } - _, err = qtx.CreateHolder(ctx, holder.Bytes()) - if err != nil && !strings.Contains(err.Error(), "UNIQUE constraint failed") { - return err - } - // if the token holder not exists, create it - _, err = qtx.CreateTokenHolder(ctx, queries.CreateTokenHolderParams{ - TokenID: th.Address().Bytes(), - HolderID: holder.Bytes(), - BlockID: th.LastBlock(), - Balance: balance.String(), - ChainID: th.ChainID, - ExternalID: th.ExternalID, - }) - if err != nil { - return err - } - created++ - continue - } - // if the calculated balance is 0 or less delete it - if balance.Cmp(big.NewInt(0)) != 1 { - if _, err := qtx.DeleteTokenHolder(ctx, queries.DeleteTokenHolderParams{ - TokenID: th.Address().Bytes(), - HolderID: holder.Bytes(), - ChainID: th.ChainID, - ExternalID: th.ExternalID, - }); err != nil { - return fmt.Errorf("error deleting token holder: %w", err) - } - deleted++ - continue - } - // if the calculated balance is the same as the current balance, skip it - currentBalance, ok := new(big.Int).SetString(currentTokenHolder.Balance, 10) - if !ok { - return fmt.Errorf("error parsing current balance: %w", err) - } - if currentBalance.Cmp(balance) == 0 { - continue - } - // if the calculated balance is not 0 or less, update it - _, err = qtx.UpdateTokenHolderBalance(ctx, queries.UpdateTokenHolderBalanceParams{ - TokenID: th.Address().Bytes(), - HolderID: holder.Bytes(), - BlockID: currentTokenHolder.BlockID, - NewBlockID: th.LastBlock(), - Balance: balance.String(), - ChainID: th.ChainID, - ExternalID: th.ExternalID, - }) - if err != nil { - return fmt.Errorf("error updating token holder: %w", err) - } - updated++ - } - if err := tx.Commit(); err != nil { - return err - } - log.Debugw("token holders saved", - "token", th.Address(), - "chainID", th.ChainID, - "externalID", th.ExternalID, - "block", th.LastBlock(), - "synced", th.IsSynced(), - "created", created, - "updated", updated, - "deleted", deleted) - th.FlushHolders() - return nil -} - -// cachedToken function returns the TokenHolders struct associated to the -// address, chainID and externalID provided. If it does not exists, it creates -// a new one and caches it getting the token information from the database. -func (s *HoldersScanner) cachedToken(ctx context.Context, addr common.Address, - chainID uint64, externalID []byte, -) (*TokenHolders, error) { - // get the token TokenHolders struct from cache, if it not exists it will - // be initialized - s.mutex.RLock() - defer s.mutex.RUnlock() - - var th *TokenHolders - for index, token := range s.tokens { - if bytes.Equal(token.Address().Bytes(), addr.Bytes()) && - token.ChainID == chainID && bytes.Equal([]byte(token.ExternalID), externalID) { - tokenHolders, err := s.db.QueriesRO.TokenHoldersByTokenIDAndChainIDAndExternalID(ctx, - queries.TokenHoldersByTokenIDAndChainIDAndExternalIDParams{ - TokenID: addr.Bytes(), - ChainID: chainID, - ExternalID: string(externalID), - }) - if err != nil { - return nil, err - } - token.FlushHolders() - for _, holder := range tokenHolders { - balance, ok := new(big.Int).SetString(holder.Balance, 10) - if !ok { - return nil, fmt.Errorf("error parsing balance: %w", err) - } - token.Append(common.BytesToAddress(holder.ID), balance) - } - s.tokens[index] = token - return token, nil - } - } - log.Infow("initializing token", "address", addr, "chainID", chainID, "externalID", externalID) - // get token information from the database - tokenInfo, err := s.db.QueriesRO.TokenByIDAndChainIDAndExternalID(ctx, queries.TokenByIDAndChainIDAndExternalIDParams{ - ID: addr.Bytes(), - ChainID: chainID, - ExternalID: string(externalID), - }) - if err != nil { - return nil, err - } - ttype := tokenInfo.TypeID - tokenLastBlock := uint64(tokenInfo.CreationBlock) - if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, addr.Bytes()); err == nil { - tokenLastBlock = blockNumber - } - th = new(TokenHolders).Init(addr, ttype, tokenLastBlock, tokenInfo.ChainID, tokenInfo.ExternalID) - tokenHolders, err := s.db.QueriesRO.TokenHoldersByTokenIDAndChainIDAndExternalID(ctx, - queries.TokenHoldersByTokenIDAndChainIDAndExternalIDParams{ - TokenID: addr.Bytes(), - ChainID: chainID, - ExternalID: string(externalID), - }) - if err != nil { - return nil, err - } - for _, holder := range tokenHolders { - balance, ok := new(big.Int).SetString(holder.Balance, 10) - if !ok { - return nil, fmt.Errorf("error parsing balance: %w", err) - } - th.Append(common.BytesToAddress(holder.ID), balance) - } - s.tokens = append(s.tokens, th) - return th, nil -} - -// scanHolders function updates the holders of the token identified by the -// address provided. It checks if the address provided already has a -// TokenHolders state cached, if not, it gets the token information from the -// HoldersScanner database and caches it. If something expected fails or the -// scan process ends successfully, the cached information is stored in the -// database. If it has no updates, it does not change anything and returns nil. -func (s *HoldersScanner) scanHolders(ctx context.Context, addr common.Address, chainID uint64, externalID []byte) (bool, error) { - log.Infow("scanning holders", "address", addr, "chainID", chainID, "externalID", externalID) - ctx, cancel := context.WithTimeout(ctx, scanIterationDurationPerToken) - defer cancel() - th, err := s.cachedToken(ctx, addr, chainID, externalID) - if err != nil { - return false, err - } - // if the token type has a external provider associated, get the holders - // from it and append it to the TokenHolders struct, then save it into the - // database and return - provider, exists := s.getProvider(th.Type()) - if !exists { - return false, fmt.Errorf("token type not supported") - } - if !provider.IsExternal() { - if err := provider.SetRef(web3.Web3ProviderRef{ - HexAddress: th.Address().Hex(), - ChainID: th.ChainID, - }); err != nil { - return th.IsSynced(), err - } - } - if err := provider.SetLastBalances(ctx, []byte(th.ExternalID), th.Holders(), th.LastBlock()); err != nil { - return false, err - } - externalBalances, lastBlock, synced, err := provider.HoldersBalances(ctx, []byte(th.ExternalID), th.LastBlock()) - if err != nil { - return false, err - } - for holder, balance := range externalBalances { - th.Append(holder, balance) - } - th.BlockDone(lastBlock) - if synced { - th.Synced() - } - // save TokesHolders state into the database before exit of the function - return synced, s.saveHolders(th) -} - -// calcTokenCreationBlock function attempts to calculate the block number when -// the token contract provided was created and deployed and updates the database -// with the result obtained. -func (s *HoldersScanner) calcTokenCreationBlock(ctx context.Context, index int) error { - if len(s.tokens) < index { - return fmt.Errorf("token not found") - } - addr := s.tokens[index].Address() - chainID := s.tokens[index].ChainID - externalID := s.tokens[index].ExternalID - // set a deadline of 10 seconds from the current context - ctx, cancel := context.WithTimeout(ctx, 10*time.Second) - defer cancel() - // get the token type - tokenInfo, err := s.db.QueriesRO.TokenByIDAndChainID(ctx, - queries.TokenByIDAndChainIDParams{ - ID: addr.Bytes(), - ChainID: chainID, - }) - if err != nil { - return fmt.Errorf("error getting token from database: %w", err) - } - provider, ok := s.getProvider(tokenInfo.TypeID) - if !ok || provider.IsExternal() { - return nil - } - if err := provider.SetRef(web3.Web3ProviderRef{ - HexAddress: addr.Hex(), - ChainID: chainID, - }); err != nil { - return fmt.Errorf("error intializing web3 client for this token: %w", err) - } - // get creation block of the current token contract - creationBlock, err := provider.CreationBlock(ctx, nil) - if err != nil { - return fmt.Errorf("error getting token creation block: %w", err) - } - // save the creation block into the database - _, err = s.db.QueriesRW.UpdateTokenCreationBlock(ctx, - queries.UpdateTokenCreationBlockParams{ - ID: addr.Bytes(), - ChainID: chainID, - ExternalID: externalID, - CreationBlock: int64(creationBlock), - }) - if err != nil { - return fmt.Errorf("error updating token creation block on the database: %w", err) - } - s.tokens[index].BlockDone(creationBlock) - return err -} diff --git a/service/tokenholders.go b/service/tokenholders.go deleted file mode 100644 index a64ca089..00000000 --- a/service/tokenholders.go +++ /dev/null @@ -1,140 +0,0 @@ -package service - -import ( - "math/big" - "sync" - "sync/atomic" - - "github.com/ethereum/go-ethereum/common" -) - -type HoldersCandidates map[common.Address]*big.Int - -// TokenHolders struct abstracts the current state of a TokenHolders into the -// Census3 HoldersScanner for a specific token. It contains some information -// about the token such as its address or its type. Also includes some atomic -// variables used to store the state of the token holders safely across -// differents goroutines, such as holders list, analyzed blocks or the last -// block analyzed. -type TokenHolders struct { - address common.Address - ctype uint64 - holders sync.Map - blocks sync.Map - lastBlock atomic.Uint64 - synced atomic.Bool - ChainID uint64 - ExternalID string -} - -// Init function fills the given TokenHolders struct with the address and type -// given, also checks the block number provided as done. It returns the -// TokenHolders struct updated. -func (h *TokenHolders) Init(addr common.Address, ctype uint64, block, chainID uint64, externalID string) *TokenHolders { - h.address = addr - h.ctype = ctype - h.holders = sync.Map{} - h.blocks = sync.Map{} - h.lastBlock.Store(block) - h.synced.Store(false) - h.ChainID = chainID - h.ExternalID = externalID - return h -} - -// Address function returns the given TokenHolders token address. -func (h *TokenHolders) Address() common.Address { - return h.address -} - -// Type function returns the given TokenHolders token type. -func (h *TokenHolders) Type() uint64 { - return h.ctype -} - -// IsReady function returns if the given TokenHolders is ready to be scanned. -// It means that the last block number is greater than 0, at least it will be -// the creation block of the token. -func (h *TokenHolders) IsReady() bool { - return h.lastBlock.Load() > 0 -} - -// Holders function returns the given TokenHolders current token holders -// addresses and its balances. -func (h *TokenHolders) Holders() HoldersCandidates { - holders := HoldersCandidates{} - h.holders.Range(func(rawAddr, rawBalance any) bool { - address, okAddr := rawAddr.(common.Address) - balance, okBalance := rawBalance.(*big.Int) - if !okAddr || !okBalance { - return true - } - - holders[address] = balance - return true - }) - return holders -} - -// Exists function returns if the given TokenHolders list of holders addresss -// includes the provided address. -func (h *TokenHolders) Exists(address common.Address) bool { - _, exists := h.holders.Load(address) - return exists -} - -// Append function appends the holder address and the balance provided into the -// given TokenHolders list of holders. If the holder already exists, it will -// update its balance. -func (h *TokenHolders) Append(addr common.Address, balance *big.Int) { - if currentBalance, exists := h.holders.Load(addr); exists { - h.holders.Store(addr, new(big.Int).Add(currentBalance.(*big.Int), balance)) - return - } - h.holders.Store(addr, balance) -} - -// Del function marks the holder address provided in the list of current -// TokenHolders as false, which means that it will be removed. -func (h *TokenHolders) Del(address common.Address) { - h.holders.Store(address, false) -} - -// FlushHolders function cleans the current list of token holders from the -// current TokenHolders state. -func (h *TokenHolders) FlushHolders() { - h.holders = sync.Map{} -} - -// BlockDone function checks the block number provided as checked appending it -// to the given TokenHolders list of blocks. If it is greater than the current -// TokenHolders block number, it will be updated. -func (h *TokenHolders) BlockDone(blockNumber uint64) { - h.blocks.Store(blockNumber, true) - h.synced.Store(false) - h.lastBlock.CompareAndSwap(h.lastBlock.Load(), blockNumber) -} - -// HasBlock function returns if the provided block number has already checked by -// the given TokenHolders. -func (h *TokenHolders) HasBlock(blockNumber uint64) bool { - _, exists := h.blocks.Load(blockNumber) - return exists -} - -// LastBlock function returns the number of latest block registered. -func (h *TokenHolders) LastBlock() uint64 { - return h.lastBlock.Load() -} - -// Synced function marks the current TokenHolders struct as synced with the -// latest network status. -func (h *TokenHolders) Synced() { - h.synced.Store(true) -} - -// IsSynced function returns if the current TokenHolders instance is already -// synced with the latest network status. -func (h *TokenHolders) IsSynced() bool { - return h.synced.Load() -} diff --git a/service/tokenholders_test.go b/service/tokenholders_test.go deleted file mode 100644 index 64ce8f2b..00000000 --- a/service/tokenholders_test.go +++ /dev/null @@ -1,137 +0,0 @@ -package service - -import ( - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/common" - qt "github.com/frankban/quicktest" - "github.com/vocdoni/census3/service/providers" -) - -func TestTokenHoldersInit(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 0, "") - c.Assert(th.address.String(), qt.Equals, MonkeysAddress.String()) - c.Assert(th.ctype, qt.Equals, providers.CONTRACT_TYPE_ERC20) - c.Assert(th.lastBlock.Load(), qt.Equals, MonkeysCreationBlock) - c.Assert(th.synced.Load(), qt.IsFalse) -} - -func TestHolders(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - c.Assert(th.address.String(), qt.Equals, MonkeysAddress.String()) - c.Assert(th.ctype, qt.Equals, providers.CONTRACT_TYPE_ERC20) - c.Assert(th.lastBlock.Load(), qt.Equals, MonkeysCreationBlock) - c.Assert(th.synced.Load(), qt.IsFalse) -} - -func TestAppend(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") - holderBalance := new(big.Int).SetUint64(16000000000000000000) - _, exists := th.holders.Load(holderAddr) - c.Assert(exists, qt.IsFalse) - th.Append(holderAddr, holderBalance) - balance, exists := th.holders.Load(holderAddr) - c.Assert(exists, qt.IsTrue) - c.Assert(balance.(*big.Int).String(), qt.Equals, holderBalance.String()) -} - -func TestExists(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") - holderBalance := new(big.Int).SetUint64(16000000000000000000) - c.Assert(th.Exists(holderAddr), qt.IsFalse) - th.Append(holderAddr, holderBalance) - c.Assert(th.Exists(holderAddr), qt.IsTrue) -} - -func TestDel(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") - holderBalance := new(big.Int).SetUint64(16000000000000000000) - th.Append(holderAddr, holderBalance) - balance, exists := th.holders.Load(holderAddr) - c.Assert(exists, qt.IsTrue) - c.Assert(balance.(*big.Int).String(), qt.Equals, holderBalance.String()) - - th.Del(holderAddr) - notRemove, exists := th.holders.Load(holderAddr) - c.Assert(exists, qt.IsTrue) - c.Assert(notRemove.(bool), qt.IsFalse) -} - -func TestFlushHolders(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - holderAddr := common.HexToAddress("0xe54d702f98E312aBA4318E3c6BDba98ab5e11012") - holderBalance := new(big.Int).SetUint64(16000000000000000000) - th.Append(holderAddr, holderBalance) - balance, exists := th.holders.Load(holderAddr) - c.Assert(exists, qt.IsTrue) - c.Assert(balance.(*big.Int).String(), qt.Equals, holderBalance.String()) - - th.FlushHolders() - _, exists = th.holders.Load(holderAddr) - c.Assert(exists, qt.IsFalse) -} - -func TestBlockDone(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - _, exists := th.blocks.Load(MonkeysCreationBlock + 500) - c.Assert(exists, qt.IsFalse) - - th.BlockDone(MonkeysCreationBlock + 500) - processed, exists := th.blocks.Load(MonkeysCreationBlock + 500) - c.Assert(exists, qt.IsTrue) - c.Assert(processed.(bool), qt.IsTrue) -} - -func TestHasBlock(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - c.Assert(th.HasBlock(MonkeysCreationBlock), qt.IsFalse) - th.BlockDone(MonkeysCreationBlock) - c.Assert(th.HasBlock(MonkeysCreationBlock), qt.IsTrue) -} - -func TestLastBlock(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - c.Assert(th.LastBlock(), qt.Equals, MonkeysCreationBlock) - th.BlockDone(MonkeysCreationBlock + 1) - c.Assert(th.LastBlock(), qt.Equals, MonkeysCreationBlock+1) - th.BlockDone(MonkeysCreationBlock + 2) - c.Assert(th.LastBlock(), qt.Equals, MonkeysCreationBlock+2) -} - -func TestSynced(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - c.Assert(th.synced.Load(), qt.IsFalse) - th.Synced() - c.Assert(th.synced.Load(), qt.IsTrue) -} - -func TestIsSynced(t *testing.T) { - c := qt.New(t) - th := new(TokenHolders).Init(MonkeysAddress, providers.CONTRACT_TYPE_ERC20, MonkeysCreationBlock, 5, "") - - c.Assert(th.IsSynced(), qt.IsFalse) - th.Synced() - c.Assert(th.IsSynced(), qt.IsTrue) -} From 0442072c8ce273da2e7e659b111b95e4d54485f5 Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Mon, 22 Jan 2024 13:29:34 +0100 Subject: [PATCH 08/35] fixing linter --- scanner/scanner.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scanner/scanner.go b/scanner/scanner.go index 2681d59b..f6fba46d 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -325,7 +325,8 @@ func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) (map[com // updates or deletes the token holders in the database depending on the // calculated balance. func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, - holders map[common.Address]*big.Int, lastBlock uint64, synced bool) error { + holders map[common.Address]*big.Int, lastBlock uint64, synced bool, +) error { log.Debugw("saving token holders", "token", token.Address.Hex(), "chainID", token.ChainID, From 3d744987704ea60c16a42e26594663a19eca7db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Wed, 24 Jan 2024 17:37:18 +0100 Subject: [PATCH 09/35] new column on tokens to count the number of analysed transfers --- api/tokens.go | 13 +- cmd/census3/main.go | 41 +-- db/migrations/0002_census3.sql | 3 +- db/migrations/0003_census3.sql | 16 ++ db/queries/holders.sql | 13 +- db/queries/tokens.sql | 17 +- db/sqlc/blocks.sql.go | 2 +- db/sqlc/censuses.sql.go | 2 +- db/sqlc/db.go | 2 +- db/sqlc/holders.sql.go | 34 +-- db/sqlc/models.go | 34 +-- db/sqlc/strategies.sql.go | 2 +- db/sqlc/tokenTypes.sql.go | 2 +- db/sqlc/tokens.sql.go | 141 ++++----- internal/metrics.go | 8 +- scanner/providers/holders_provider.go | 2 +- scanner/providers/poap/poap_provider.go | 6 +- scanner/providers/types.go | 32 +-- scanner/providers/web3/const.go | 4 - scanner/providers/web3/endpoint.go | 2 + scanner/providers/web3/erc20_provider.go | 110 +++---- scanner/providers/web3/erc721_provider.go | 265 +++++++++++++++++ scanner/providers/web3/erc777_provider.go | 265 +++++++++++++++++ scanner/providers/web3/helpers.go | 50 ---- scanner/providers/web3/web3_provider.go | 134 +++++++++ scanner/scanner.go | 335 +++++++++++----------- 26 files changed, 1056 insertions(+), 479 deletions(-) create mode 100644 db/migrations/0003_census3.sql create mode 100644 scanner/providers/web3/erc721_provider.go create mode 100644 scanner/providers/web3/erc777_provider.go delete mode 100644 scanner/providers/web3/helpers.go diff --git a/api/tokens.go b/api/tokens.go index 84dbdbfe..a364ed59 100644 --- a/api/tokens.go +++ b/api/tokens.go @@ -468,16 +468,9 @@ func (capi *census3API) getToken(msg *api.APIdata, ctx *httprouter.HTTPContext) } return ErrCantGetToken.WithErr(err) } - // get last block with token information - atBlock, err := capi.db.QueriesRO.LastBlockByTokenID(internalCtx, address.Bytes()) - if err != nil { - if !errors.Is(err, sql.ErrNoRows) { - return ErrCantGetToken.WithErr(err) - } - atBlock = 0 - } // if the token is not synced, get the last block of the network to // calculate the current scan progress + atBlock := uint64(tokenData.LastBlock) tokenProgress := 100 if !tokenData.Synced { provider, exists := capi.holderProviders[tokenData.TypeID] @@ -497,7 +490,9 @@ func (capi *census3API) getToken(msg *api.APIdata, ctx *httprouter.HTTPContext) if err != nil { return ErrCantGetLastBlockNumber.WithErr(err) } - tokenProgress = int(float64(atBlock) / float64(lastBlockNumber) * 100) + lastBlockNumber -= uint64(tokenData.CreationBlock) + currentBlockNumber := atBlock - uint64(tokenData.CreationBlock) + tokenProgress = int(float64(currentBlockNumber) / float64(lastBlockNumber) * 100) } // get token holders count holders, err := capi.db.QueriesRO.CountTokenHolders(internalCtx, diff --git a/cmd/census3/main.go b/cmd/census3/main.go index 1ddd445a..e7c87a3a 100644 --- a/cmd/census3/main.go +++ b/cmd/census3/main.go @@ -117,11 +117,19 @@ func main() { if err != nil { log.Fatal(err) } - // init the ERC20 token providers + // init the web3 token providers erc20Provider := new(web3.ERC20HolderProvider) if err := erc20Provider.Init(web3.Web3ProviderConfig{Endpoints: w3p}); err != nil { log.Fatal(err) } + erc721Provider := new(web3.ERC721HolderProvider) + if err := erc721Provider.Init(web3.Web3ProviderConfig{Endpoints: w3p}); err != nil { + log.Fatal(err) + } + erc777Provider := new(web3.ERC777HolderProvider) + if err := erc777Provider.Init(web3.Web3ProviderConfig{Endpoints: w3p}); err != nil { + log.Fatal(err) + } // init POAP external provider poapProvider := new(poap.POAPHolderProvider) if err := poapProvider.Init(poap.POAPConfig{ @@ -130,12 +138,9 @@ func main() { }); err != nil { log.Fatal(err) } - holderProviders := map[uint64]providers.HolderProvider{ - providers.CONTRACT_TYPE_ERC20: erc20Provider, - providers.CONTRACT_TYPE_POAP: poapProvider, - } // start the holder scanner with the database and the providers - hc := scanner.NewScanner(database, w3p, holderProviders, config.scannerCoolDown) + hc := scanner.NewScanner(database, w3p, config.scannerCoolDown) + hc.SetProviders(erc20Provider, erc721Provider, erc777Provider, poapProvider) // if the admin token is not defined, generate a random one if config.adminToken != "" { if _, err := uuid.Parse(config.adminToken); err != nil { @@ -147,13 +152,18 @@ func main() { } // Start the API apiService, err := api.Init(database, api.Census3APIConf{ - Hostname: "0.0.0.0", - Port: config.port, - DataDir: config.dataDir, - Web3Providers: w3p, - GroupKey: config.connectKey, - HolderProviders: holderProviders, - AdminToken: config.adminToken, + Hostname: "0.0.0.0", + Port: config.port, + DataDir: config.dataDir, + Web3Providers: w3p, + GroupKey: config.connectKey, + HolderProviders: map[uint64]providers.HolderProvider{ + providers.CONTRACT_TYPE_ERC20: erc20Provider, + providers.CONTRACT_TYPE_ERC721: erc721Provider, + providers.CONTRACT_TYPE_ERC777: erc777Provider, + providers.CONTRACT_TYPE_POAP: poapProvider, + }, + AdminToken: config.adminToken, }) if err != nil { log.Fatal(err) @@ -180,11 +190,6 @@ func main() { if err := database.Close(); err != nil { log.Fatal(err) } - for _, provider := range holderProviders { - if err := provider.Close(); err != nil { - log.Fatal(err) - } - } log.Infof("all routines ended") }() time.Sleep(5 * time.Second) diff --git a/db/migrations/0002_census3.sql b/db/migrations/0002_census3.sql index c485efee..ec724b4d 100644 --- a/db/migrations/0002_census3.sql +++ b/db/migrations/0002_census3.sql @@ -2,5 +2,6 @@ -- +goose Up ALTER TABLE censuses ADD COLUMN accuracy FLOAT NOT NULL DEFAULT '100.0'; + -- List of changes: --- * Add 'accuracy' column to 'census' table \ No newline at end of file +-- * Add 'accuracy' column to 'censuses' table \ No newline at end of file diff --git a/db/migrations/0003_census3.sql b/db/migrations/0003_census3.sql new file mode 100644 index 00000000..596cb932 --- /dev/null +++ b/db/migrations/0003_census3.sql @@ -0,0 +1,16 @@ + +-- +goose Up +DELETE FROM token_types; +UPDATE sqlite_sequence SET seq = 0 WHERE name = 'token_types'; +INSERT INTO token_types (type_name) VALUES ('erc20'); +INSERT INTO token_types (type_name) VALUES ('erc721');; +INSERT INTO token_types (type_name) VALUES ('erc777'); +INSERT INTO token_types (type_name) VALUES ('poap'); + +ALTER TABLE tokens ADD COLUMN last_block BIGINT NOT NULL DEFAULT 0; +ALTER TABLE tokens ADD COLUMN analysed_transfers BIGINT NOT NULL DEFAULT 0; + +-- List of changes: +-- * Remove all token types and reset sequence +-- * Add 'last_block' column to 'tokens' table +-- * Add 'analysed_transfers' column to 'tokens' table \ No newline at end of file diff --git a/db/queries/holders.sql b/db/queries/holders.sql index f30612bb..d8aa1e81 100644 --- a/db/queries/holders.sql +++ b/db/queries/holders.sql @@ -35,13 +35,12 @@ AND token_holders.chain_id = ? AND token_holders.holder_id = ?; -- name: TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID :one -SELECT holders.*, token_holders.* -FROM holders -JOIN token_holders ON holders.id = token_holders.holder_id -WHERE token_holders.token_id = ? - AND token_holders.holder_id = ? - AND token_holders.chain_id = ? - AND token_holders.external_id = ?; +SELECT * +FROM token_holders +WHERE token_id = ? + AND holder_id = ? + AND chain_id = ? + AND external_id = ?; -- name: TokenHolderByTokenIDAndBlockIDAndHolderID :one SELECT holders.*, token_holders.balance diff --git a/db/queries/tokens.sql b/db/queries/tokens.sql index ef0d5832..31382464 100644 --- a/db/queries/tokens.sql +++ b/db/queries/tokens.sql @@ -5,13 +5,7 @@ WHERE strftime('%s', 'now') - strftime('%s', created_at) <= 600 ORDER BY created_at DESC; -- name: ListOldNoSyncedTokens :many -SELECT tokens.*, ( - SELECT MAX(block_id) AS last_block - FROM token_holders - WHERE token_id = tokens.id - AND chain_id = tokens.chain_id - AND external_id = tokens.external_id -) FROM tokens +SELECT * FROM tokens WHERE strftime('%s', 'now') - strftime('%s', created_at) > 600 AND synced = 0; @@ -76,15 +70,18 @@ VALUES ( -- name: UpdateTokenStatus :execresult UPDATE tokens -SET synced = sqlc.arg(synced) +SET synced = sqlc.arg(synced), + last_block = sqlc.arg(last_block), + analysed_transfers = sqlc.arg(analysed_transfers) WHERE id = sqlc.arg(id) AND chain_id = sqlc.arg(chain_id) AND external_id = sqlc.arg(external_id); --- name: UpdateTokenCreationBlock :execresult +-- name: UpdateTokenBlocks :execresult UPDATE tokens -SET creation_block = sqlc.arg(creation_block) +SET creation_block = sqlc.arg(creation_block), + last_block = sqlc.arg(last_block) WHERE id = sqlc.arg(id) AND chain_id = sqlc.arg(chain_id) AND external_id = sqlc.arg(external_id); diff --git a/db/sqlc/blocks.sql.go b/db/sqlc/blocks.sql.go index 87d84ea3..2b39e6ed 100644 --- a/db/sqlc/blocks.sql.go +++ b/db/sqlc/blocks.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.24.0 +// sqlc v1.25.0 // source: blocks.sql package queries diff --git a/db/sqlc/censuses.sql.go b/db/sqlc/censuses.sql.go index ed1e74f9..852c8bf5 100644 --- a/db/sqlc/censuses.sql.go +++ b/db/sqlc/censuses.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.24.0 +// sqlc v1.25.0 // source: censuses.sql package queries diff --git a/db/sqlc/db.go b/db/sqlc/db.go index d4cdb252..ef8b0c29 100644 --- a/db/sqlc/db.go +++ b/db/sqlc/db.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.24.0 +// sqlc v1.25.0 package queries diff --git a/db/sqlc/holders.sql.go b/db/sqlc/holders.sql.go index b9c6fff3..aa387aca 100644 --- a/db/sqlc/holders.sql.go +++ b/db/sqlc/holders.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.24.0 +// sqlc v1.25.0 // source: holders.sql package queries @@ -396,13 +396,12 @@ func (q *Queries) TokenHolderByTokenIDAndHolderID(ctx context.Context, arg Token } const tokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID = `-- name: TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID :one -SELECT holders.id, token_holders.token_id, token_holders.holder_id, token_holders.balance, token_holders.block_id, token_holders.chain_id, token_holders.external_id -FROM holders -JOIN token_holders ON holders.id = token_holders.holder_id -WHERE token_holders.token_id = ? - AND token_holders.holder_id = ? - AND token_holders.chain_id = ? - AND token_holders.external_id = ? +SELECT token_id, holder_id, balance, block_id, chain_id, external_id +FROM token_holders +WHERE token_id = ? + AND holder_id = ? + AND chain_id = ? + AND external_id = ? ` type TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDParams struct { @@ -412,26 +411,15 @@ type TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDParams struct { ExternalID string } -type TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDRow struct { - ID annotations.Address - TokenID annotations.Address - HolderID annotations.Address - Balance string - BlockID uint64 - ChainID uint64 - ExternalID string -} - -func (q *Queries) TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID(ctx context.Context, arg TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDParams) (TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDRow, error) { +func (q *Queries) TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID(ctx context.Context, arg TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDParams) (TokenHolder, error) { row := q.db.QueryRowContext(ctx, tokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID, arg.TokenID, arg.HolderID, arg.ChainID, arg.ExternalID, ) - var i TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDRow + var i TokenHolder err := row.Scan( - &i.ID, &i.TokenID, &i.HolderID, &i.Balance, @@ -648,7 +636,7 @@ func (q *Queries) TokenHoldersByTokenIDAndExternalID(ctx context.Context, arg To } const tokensByHolderID = `-- name: TokensByHolderID :many -SELECT tokens.id, tokens.name, tokens.symbol, tokens.decimals, tokens.total_supply, tokens.creation_block, tokens.type_id, tokens.synced, tokens.tags, tokens.chain_id, tokens.chain_address, tokens.external_id, tokens.default_strategy, tokens.icon_uri, tokens.created_at +SELECT tokens.id, tokens.name, tokens.symbol, tokens.decimals, tokens.total_supply, tokens.creation_block, tokens.type_id, tokens.synced, tokens.tags, tokens.chain_id, tokens.chain_address, tokens.external_id, tokens.default_strategy, tokens.icon_uri, tokens.created_at, tokens.last_block, tokens.analysed_transfers FROM tokens JOIN token_holders ON tokens.id = token_holders.token_id WHERE token_holders.holder_id = ? @@ -679,6 +667,8 @@ func (q *Queries) TokensByHolderID(ctx context.Context, holderID annotations.Add &i.DefaultStrategy, &i.IconUri, &i.CreatedAt, + &i.LastBlock, + &i.AnalysedTransfers, ); err != nil { return nil, err } diff --git a/db/sqlc/models.go b/db/sqlc/models.go index 2f288b5f..4ddf36e0 100644 --- a/db/sqlc/models.go +++ b/db/sqlc/models.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.24.0 +// sqlc v1.25.0 package queries @@ -54,21 +54,23 @@ type StrategyToken struct { } type Token struct { - ID annotations.Address - Name string - Symbol string - Decimals uint64 - TotalSupply annotations.BigInt - CreationBlock int64 - TypeID uint64 - Synced bool - Tags string - ChainID uint64 - ChainAddress string - ExternalID string - DefaultStrategy uint64 - IconUri string - CreatedAt time.Time + ID annotations.Address + Name string + Symbol string + Decimals uint64 + TotalSupply annotations.BigInt + CreationBlock int64 + TypeID uint64 + Synced bool + Tags string + ChainID uint64 + ChainAddress string + ExternalID string + DefaultStrategy uint64 + IconUri string + CreatedAt time.Time + LastBlock int64 + AnalysedTransfers int64 } type TokenHolder struct { diff --git a/db/sqlc/strategies.sql.go b/db/sqlc/strategies.sql.go index 8b7f3b9c..5d85c1d2 100644 --- a/db/sqlc/strategies.sql.go +++ b/db/sqlc/strategies.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.24.0 +// sqlc v1.25.0 // source: strategies.sql package queries diff --git a/db/sqlc/tokenTypes.sql.go b/db/sqlc/tokenTypes.sql.go index 3d4ecc67..53f28194 100644 --- a/db/sqlc/tokenTypes.sql.go +++ b/db/sqlc/tokenTypes.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.24.0 +// sqlc v1.25.0 // source: tokenTypes.sql package queries diff --git a/db/sqlc/tokens.sql.go b/db/sqlc/tokens.sql.go index df188401..b8eac82d 100644 --- a/db/sqlc/tokens.sql.go +++ b/db/sqlc/tokens.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.24.0 +// sqlc v1.25.0 // source: tokens.sql package queries @@ -156,7 +156,7 @@ func (q *Queries) ExistsTokenByChainIDAndExternalID(ctx context.Context, arg Exi } const listLastNoSyncedTokens = `-- name: ListLastNoSyncedTokens :many -SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at FROM tokens +SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM tokens WHERE strftime('%s', 'now') - strftime('%s', created_at) <= 600 AND synced = 0 ORDER BY created_at DESC @@ -187,6 +187,8 @@ func (q *Queries) ListLastNoSyncedTokens(ctx context.Context) ([]Token, error) { &i.DefaultStrategy, &i.IconUri, &i.CreatedAt, + &i.LastBlock, + &i.AnalysedTransfers, ); err != nil { return nil, err } @@ -202,45 +204,20 @@ func (q *Queries) ListLastNoSyncedTokens(ctx context.Context) ([]Token, error) { } const listOldNoSyncedTokens = `-- name: ListOldNoSyncedTokens :many -SELECT tokens.id, tokens.name, tokens.symbol, tokens.decimals, tokens.total_supply, tokens.creation_block, tokens.type_id, tokens.synced, tokens.tags, tokens.chain_id, tokens.chain_address, tokens.external_id, tokens.default_strategy, tokens.icon_uri, tokens.created_at, ( - SELECT MAX(block_id) AS last_block - FROM token_holders - WHERE token_id = tokens.id - AND chain_id = tokens.chain_id - AND external_id = tokens.external_id -) FROM tokens +SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM tokens WHERE strftime('%s', 'now') - strftime('%s', created_at) > 600 AND synced = 0 ` -type ListOldNoSyncedTokensRow struct { - ID annotations.Address - Name string - Symbol string - Decimals uint64 - TotalSupply annotations.BigInt - CreationBlock int64 - TypeID uint64 - Synced bool - Tags string - ChainID uint64 - ChainAddress string - ExternalID string - DefaultStrategy uint64 - IconUri string - CreatedAt time.Time - LastBlock interface{} -} - -func (q *Queries) ListOldNoSyncedTokens(ctx context.Context) ([]ListOldNoSyncedTokensRow, error) { +func (q *Queries) ListOldNoSyncedTokens(ctx context.Context) ([]Token, error) { rows, err := q.db.QueryContext(ctx, listOldNoSyncedTokens) if err != nil { return nil, err } defer rows.Close() - var items []ListOldNoSyncedTokensRow + var items []Token for rows.Next() { - var i ListOldNoSyncedTokensRow + var i Token if err := rows.Scan( &i.ID, &i.Name, @@ -258,6 +235,7 @@ func (q *Queries) ListOldNoSyncedTokens(ctx context.Context) ([]ListOldNoSyncedT &i.IconUri, &i.CreatedAt, &i.LastBlock, + &i.AnalysedTransfers, ); err != nil { return nil, err } @@ -273,7 +251,7 @@ func (q *Queries) ListOldNoSyncedTokens(ctx context.Context) ([]ListOldNoSyncedT } const listSyncedTokens = `-- name: ListSyncedTokens :many -SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at FROM tokens WHERE synced = 1 +SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM tokens WHERE synced = 1 ` func (q *Queries) ListSyncedTokens(ctx context.Context) ([]Token, error) { @@ -301,6 +279,8 @@ func (q *Queries) ListSyncedTokens(ctx context.Context) ([]Token, error) { &i.DefaultStrategy, &i.IconUri, &i.CreatedAt, + &i.LastBlock, + &i.AnalysedTransfers, ); err != nil { return nil, err } @@ -316,7 +296,7 @@ func (q *Queries) ListSyncedTokens(ctx context.Context) ([]Token, error) { } const nextTokensPage = `-- name: NextTokensPage :many -SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at FROM tokens +SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM tokens WHERE id >= ? ORDER BY id ASC LIMIT ? @@ -352,6 +332,8 @@ func (q *Queries) NextTokensPage(ctx context.Context, arg NextTokensPageParams) &i.DefaultStrategy, &i.IconUri, &i.CreatedAt, + &i.LastBlock, + &i.AnalysedTransfers, ); err != nil { return nil, err } @@ -367,8 +349,8 @@ func (q *Queries) NextTokensPage(ctx context.Context, arg NextTokensPageParams) } const prevTokensPage = `-- name: PrevTokensPage :many -SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at FROM ( - SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at FROM tokens +SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM ( + SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM tokens WHERE id <= ? ORDER BY id DESC LIMIT ? @@ -405,6 +387,8 @@ func (q *Queries) PrevTokensPage(ctx context.Context, arg PrevTokensPageParams) &i.DefaultStrategy, &i.IconUri, &i.CreatedAt, + &i.LastBlock, + &i.AnalysedTransfers, ); err != nil { return nil, err } @@ -420,7 +404,7 @@ func (q *Queries) PrevTokensPage(ctx context.Context, arg PrevTokensPageParams) } const tokenByID = `-- name: TokenByID :one -SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at FROM tokens +SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM tokens WHERE id = ? LIMIT 1 ` @@ -444,12 +428,14 @@ func (q *Queries) TokenByID(ctx context.Context, id annotations.Address) (Token, &i.DefaultStrategy, &i.IconUri, &i.CreatedAt, + &i.LastBlock, + &i.AnalysedTransfers, ) return i, err } const tokenByIDAndChainID = `-- name: TokenByIDAndChainID :one -SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at FROM tokens +SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM tokens WHERE id = ? AND chain_id = ? LIMIT 1 ` @@ -478,12 +464,14 @@ func (q *Queries) TokenByIDAndChainID(ctx context.Context, arg TokenByIDAndChain &i.DefaultStrategy, &i.IconUri, &i.CreatedAt, + &i.LastBlock, + &i.AnalysedTransfers, ) return i, err } const tokenByIDAndChainIDAndExternalID = `-- name: TokenByIDAndChainIDAndExternalID :one -SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at FROM tokens +SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM tokens WHERE id = ? AND chain_id = ? AND external_id = ? LIMIT 1 ` @@ -513,38 +501,42 @@ func (q *Queries) TokenByIDAndChainIDAndExternalID(ctx context.Context, arg Toke &i.DefaultStrategy, &i.IconUri, &i.CreatedAt, + &i.LastBlock, + &i.AnalysedTransfers, ) return i, err } const tokensByStrategyID = `-- name: TokensByStrategyID :many -SELECT t.id, t.name, t.symbol, t.decimals, t.total_supply, t.creation_block, t.type_id, t.synced, t.tags, t.chain_id, t.chain_address, t.external_id, t.default_strategy, t.icon_uri, t.created_at, st.strategy_id, st.token_id, st.min_balance, st.chain_id, st.external_id FROM tokens t +SELECT t.id, t.name, t.symbol, t.decimals, t.total_supply, t.creation_block, t.type_id, t.synced, t.tags, t.chain_id, t.chain_address, t.external_id, t.default_strategy, t.icon_uri, t.created_at, t.last_block, t.analysed_transfers, st.strategy_id, st.token_id, st.min_balance, st.chain_id, st.external_id FROM tokens t JOIN strategy_tokens st ON st.token_id = t.id WHERE st.strategy_id = ? ORDER BY t.name ` type TokensByStrategyIDRow struct { - ID annotations.Address - Name string - Symbol string - Decimals uint64 - TotalSupply annotations.BigInt - CreationBlock int64 - TypeID uint64 - Synced bool - Tags string - ChainID uint64 - ChainAddress string - ExternalID string - DefaultStrategy uint64 - IconUri string - CreatedAt time.Time - StrategyID uint64 - TokenID []byte - MinBalance string - ChainID_2 uint64 - ExternalID_2 string + ID annotations.Address + Name string + Symbol string + Decimals uint64 + TotalSupply annotations.BigInt + CreationBlock int64 + TypeID uint64 + Synced bool + Tags string + ChainID uint64 + ChainAddress string + ExternalID string + DefaultStrategy uint64 + IconUri string + CreatedAt time.Time + LastBlock int64 + AnalysedTransfers int64 + StrategyID uint64 + TokenID []byte + MinBalance string + ChainID_2 uint64 + ExternalID_2 string } func (q *Queries) TokensByStrategyID(ctx context.Context, strategyID uint64) ([]TokensByStrategyIDRow, error) { @@ -572,6 +564,8 @@ func (q *Queries) TokensByStrategyID(ctx context.Context, strategyID uint64) ([] &i.DefaultStrategy, &i.IconUri, &i.CreatedAt, + &i.LastBlock, + &i.AnalysedTransfers, &i.StrategyID, &i.TokenID, &i.MinBalance, @@ -591,24 +585,27 @@ func (q *Queries) TokensByStrategyID(ctx context.Context, strategyID uint64) ([] return items, nil } -const updateTokenCreationBlock = `-- name: UpdateTokenCreationBlock :execresult +const updateTokenBlocks = `-- name: UpdateTokenBlocks :execresult UPDATE tokens -SET creation_block = ? +SET creation_block = ?, + last_block = ? WHERE id = ? AND chain_id = ? AND external_id = ? ` -type UpdateTokenCreationBlockParams struct { +type UpdateTokenBlocksParams struct { CreationBlock int64 + LastBlock int64 ID annotations.Address ChainID uint64 ExternalID string } -func (q *Queries) UpdateTokenCreationBlock(ctx context.Context, arg UpdateTokenCreationBlockParams) (sql.Result, error) { - return q.db.ExecContext(ctx, updateTokenCreationBlock, +func (q *Queries) UpdateTokenBlocks(ctx context.Context, arg UpdateTokenBlocksParams) (sql.Result, error) { + return q.db.ExecContext(ctx, updateTokenBlocks, arg.CreationBlock, + arg.LastBlock, arg.ID, arg.ChainID, arg.ExternalID, @@ -641,22 +638,28 @@ func (q *Queries) UpdateTokenDefaultStrategy(ctx context.Context, arg UpdateToke const updateTokenStatus = `-- name: UpdateTokenStatus :execresult UPDATE tokens -SET synced = ? +SET synced = ?, + last_block = ?, + analysed_transfers = ? WHERE id = ? AND chain_id = ? AND external_id = ? ` type UpdateTokenStatusParams struct { - Synced bool - ID annotations.Address - ChainID uint64 - ExternalID string + Synced bool + LastBlock int64 + AnalysedTransfers int64 + ID annotations.Address + ChainID uint64 + ExternalID string } func (q *Queries) UpdateTokenStatus(ctx context.Context, arg UpdateTokenStatusParams) (sql.Result, error) { return q.db.ExecContext(ctx, updateTokenStatus, arg.Synced, + arg.LastBlock, + arg.AnalysedTransfers, arg.ID, arg.ChainID, arg.ExternalID, diff --git a/internal/metrics.go b/internal/metrics.go index a36dfcd0..1f0d8156 100644 --- a/internal/metrics.go +++ b/internal/metrics.go @@ -1,6 +1,10 @@ package internal -import "github.com/VictoriaMetrics/metrics" +import ( + "sync/atomic" + + "github.com/VictoriaMetrics/metrics" +) const ( LastAnalysedBlockByChainPrefix = `census3_last_analysed_block_by_chain_` @@ -26,6 +30,8 @@ var ( TotalNumberOfCensuses = metrics.NewCounter(`census3_total_number_of_censuses`) // number of censuses by type (anonymous or not) NumberOfCensusesByType = metrics.NewSet() + + GetBlockByNumberCounter = atomic.Uint64{} ) func init() { diff --git a/scanner/providers/holders_provider.go b/scanner/providers/holders_provider.go index 5bc76711..574716a3 100644 --- a/scanner/providers/holders_provider.go +++ b/scanner/providers/holders_provider.go @@ -24,7 +24,7 @@ type HolderProvider interface { SetLastBalances(ctx context.Context, id []byte, balances map[common.Address]*big.Int, from uint64) error // HoldersBalances returns the balances of the token holders for the given // id and delta point in time, from the stored last snapshot. - HoldersBalances(ctx context.Context, id []byte, to uint64) (map[common.Address]*big.Int, uint64, bool, error) + HoldersBalances(ctx context.Context, id []byte, to uint64) (map[common.Address]*big.Int, uint64, uint64, bool, error) // Close closes the provider and its internal structures. Close() error IsExternal() bool diff --git a/scanner/providers/poap/poap_provider.go b/scanner/providers/poap/poap_provider.go index 7af4218a..845ca593 100644 --- a/scanner/providers/poap/poap_provider.go +++ b/scanner/providers/poap/poap_provider.go @@ -118,14 +118,14 @@ func (p *POAPHolderProvider) SetLastBalances(_ context.Context, id []byte, // API parsing every POAP holder for the event ID provided and calculate the // balances of the token holders from the last snapshot. func (p *POAPHolderProvider) HoldersBalances(_ context.Context, id []byte, delta uint64) ( - map[common.Address]*big.Int, uint64, bool, error, + map[common.Address]*big.Int, uint64, uint64, bool, error, ) { // parse eventID from id eventID := string(id) // get last snapshot newSnapshot, err := p.lastHolders(eventID) if err != nil { - return nil, 0, false, err + return nil, 0, 0, false, err } // calculate snapshot from from := delta @@ -142,7 +142,7 @@ func (p *POAPHolderProvider) HoldersBalances(_ context.Context, id []byte, delta snapshot: newSnapshot, } // return partials from last snapshot - return partialBalances, from, true, nil + return partialBalances, 1, from, true, nil } // Close method is not implemented in the POAP external provider. By default it diff --git a/scanner/providers/types.go b/scanner/providers/types.go index 3dd6b82e..eca3fee1 100644 --- a/scanner/providers/types.go +++ b/scanner/providers/types.go @@ -5,34 +5,22 @@ const ( CONTRACT_TYPE_UNKNOWN uint64 = iota CONTRACT_TYPE_ERC20 CONTRACT_TYPE_ERC721 - CONTRACT_TYPE_ERC1155 CONTRACT_TYPE_ERC777 - CONTRACT_TYPE_CUSTOM_NATION3_VENATION - CONTRACT_TYPE_CUSTOM_ARAGON_WANT - CONTRACT_TYPE_ERC721_BURNED CONTRACT_TYPE_POAP ) var TokenTypeStringMap = map[uint64]string{ - CONTRACT_TYPE_UNKNOWN: "unknown", - CONTRACT_TYPE_ERC20: "erc20", - CONTRACT_TYPE_ERC721_BURNED: "erc721burned", - CONTRACT_TYPE_ERC1155: "erc1155", - CONTRACT_TYPE_ERC777: "erc777", - CONTRACT_TYPE_CUSTOM_NATION3_VENATION: "nation3", - CONTRACT_TYPE_CUSTOM_ARAGON_WANT: "want", - CONTRACT_TYPE_ERC721: "erc721", - CONTRACT_TYPE_POAP: "poap", + CONTRACT_TYPE_UNKNOWN: "unknown", + CONTRACT_TYPE_ERC20: "erc20", + CONTRACT_TYPE_ERC721: "erc721", + CONTRACT_TYPE_ERC777: "erc777", + CONTRACT_TYPE_POAP: "poap", } var TokenTypeIntMap = map[string]uint64{ - "unknown": CONTRACT_TYPE_UNKNOWN, - "erc20": CONTRACT_TYPE_ERC20, - "erc721": CONTRACT_TYPE_ERC721, - "erc1155": CONTRACT_TYPE_ERC1155, - "erc777": CONTRACT_TYPE_ERC777, - "nation3": CONTRACT_TYPE_CUSTOM_NATION3_VENATION, - "want": CONTRACT_TYPE_CUSTOM_ARAGON_WANT, - "erc721burned": CONTRACT_TYPE_ERC721_BURNED, - "poap": CONTRACT_TYPE_POAP, + "unknown": CONTRACT_TYPE_UNKNOWN, + "erc20": CONTRACT_TYPE_ERC20, + "erc721": CONTRACT_TYPE_ERC721, + "erc777": CONTRACT_TYPE_ERC777, + "poap": CONTRACT_TYPE_POAP, } diff --git a/scanner/providers/web3/const.go b/scanner/providers/web3/const.go index 59cb6c57..666eb307 100644 --- a/scanner/providers/web3/const.go +++ b/scanner/providers/web3/const.go @@ -30,12 +30,8 @@ const ( const ( // EVM LOG TOPICS - LOG_TOPIC_VENATION_DEPOSIT = "4566dfc29f6f11d13a418c26a02bef7c28bae749d4de47e4e6a7cddea6730d59" - LOG_TOPIC_VENATION_WITHDRAW = "f279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568" LOG_TOPIC_ERC20_TRANSFER = "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" LOG_TOPIC_ERC1155_TRANSFER_SINGLE = "c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62" LOG_TOPIC_ERC1155_TRANSFER_BATCH = "4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb" - LOG_TOPIC_WANT_DEPOSIT = "e1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c" - LOG_TOPIC_WANT_WITHDRAWAL = "7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65" // Add more topics here ) diff --git a/scanner/providers/web3/endpoint.go b/scanner/providers/web3/endpoint.go index 04614cfb..cd47d771 100644 --- a/scanner/providers/web3/endpoint.go +++ b/scanner/providers/web3/endpoint.go @@ -8,6 +8,7 @@ import ( "os" "github.com/ethereum/go-ethereum/ethclient" + "github.com/vocdoni/census3/internal" "go.vocdoni.io/dvote/log" ) @@ -114,6 +115,7 @@ func (nps NetworkEndpoints) CurrentBlockNumbers(ctx context.Context) (map[uint64 if err != nil { return blockNumbers, err } + internal.GetBlockByNumberCounter.Add(1) blockNumber, err := cli.BlockNumber(ctx) if err != nil { return blockNumbers, fmt.Errorf("error getting the block number from %s network: %w", endpoint.Name, err) diff --git a/scanner/providers/web3/erc20_provider.go b/scanner/providers/web3/erc20_provider.go index e5ddd4a0..1f16f4e3 100644 --- a/scanner/providers/web3/erc20_provider.go +++ b/scanner/providers/web3/erc20_provider.go @@ -5,14 +5,13 @@ import ( "errors" "fmt" "math/big" - "strings" "sync" "time" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" erc20 "github.com/vocdoni/census3/contracts/erc/erc20" + "github.com/vocdoni/census3/internal" "github.com/vocdoni/census3/scanner/providers" "go.vocdoni.io/dvote/log" ) @@ -90,6 +89,7 @@ func (p *ERC20HolderProvider) SetRef(iref any) error { p.balancesMtx.Lock() defer p.balancesMtx.Unlock() p.balances = make(map[common.Address]*big.Int) + p.balancesBlock = 0 return nil } @@ -108,21 +108,14 @@ func (p *ERC20HolderProvider) SetLastBalances(ctx context.Context, id []byte, } func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fromBlock uint64) ( - map[common.Address]*big.Int, uint64, bool, error, + map[common.Address]*big.Int, uint64, uint64, bool, error, ) { // calculate the range of blocks to scan, by default take the last block // scanned and scan to the latest block toBlock, err := p.LatestBlockNumber(ctx, nil) if err != nil { - return nil, fromBlock, false, err + return nil, 0, fromBlock, false, err } - // if the range is too big, scan only a part of it using the constant - // BLOCKS_TO_SCAN_AT_ONCE - if toBlock-fromBlock > BLOCKS_TO_SCAN_AT_ONCE { - toBlock = fromBlock + MAX_SCAN_BLOCKS_PER_ITERATION - } - logCount := 0 - blocksRange := BLOCKS_TO_SCAN_AT_ONCE log.Infow("scan iteration", "address", p.address, "type", providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC20], @@ -130,85 +123,47 @@ func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fro "to", toBlock) // some variables to calculate the progress startTime := time.Now() - initialBlock := fromBlock - lastBlock := fromBlock p.balancesMtx.RLock() initialHolders := len(p.balances) p.balancesMtx.RUnlock() // iterate scanning the logs in the range of blocks until the last block // is reached - for fromBlock < toBlock { - select { - case <-ctx.Done(): - log.Warnf("scan graceful canceled by context") - return p.balances, lastBlock, false, nil - default: - if logCount > MAX_SCAN_LOGS_PER_ITERATION { - return p.balances, lastBlock, false, nil - } - // compose the filter to get the logs of the ERC20 Transfer events - filter := ethereum.FilterQuery{ - Addresses: []common.Address{p.address}, - FromBlock: new(big.Int).SetUint64(fromBlock), - ToBlock: new(big.Int).SetUint64(fromBlock + blocksRange), - Topics: [][]common.Hash{ - {common.HexToHash(LOG_TOPIC_ERC20_TRANSFER)}, - }, - } - // get the logs and check if there are any errors - logs, err := p.client.FilterLogs(ctx, filter) - if err != nil { - // if the error is about the query returning more than the maximum - // allowed logs, split the range of blocks in half and try again - if strings.Contains(err.Error(), "query returned more than") { - blocksRange /= 2 - log.Warnf("too much results on query, decreasing blocks to %d", blocksRange) - continue - } - return nil, lastBlock, false, errors.Join(ErrScanningTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.address, err)) - } - // if there are no logs, the range of blocks is empty, so return the - // balances - if len(logs) == 0 { - fromBlock += blocksRange - continue - } - logCount += len(logs) - // iterate the logs and update the balances - for _, log := range logs { - logData, err := p.contract.ERC20ContractFilterer.ParseTransfer(log) - if err != nil { - return nil, lastBlock, false, errors.Join(ErrParsingTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.address, err)) - } - // update balances - p.balancesMtx.Lock() - if toBalance, ok := p.balances[logData.To]; ok { - p.balances[logData.To] = new(big.Int).Add(toBalance, logData.Value) - } else { - p.balances[logData.To] = logData.Value - } - if fromBalance, ok := p.balances[logData.From]; ok { - p.balances[logData.From] = new(big.Int).Sub(fromBalance, logData.Value) - } else { - p.balances[logData.From] = new(big.Int).Neg(logData.Value) - } - p.balancesMtx.Unlock() - lastBlock = log.BlockNumber - } - // update the fromBlock to the last block scanned - fromBlock += blocksRange + logs, lastBlock, synced, err := rangeOfLogs(ctx, p.client, p.address, fromBlock, toBlock, LOG_TOPIC_ERC20_TRANSFER) + if err != nil { + return nil, 0, fromBlock, false, err + } + // encode the number of new transfers + newTransfers := uint64(len(logs)) + // iterate the logs and update the balances + for _, currentLog := range logs { + logData, err := p.contract.ERC20ContractFilterer.ParseTransfer(currentLog) + if err != nil { + return nil, newTransfers, lastBlock, false, errors.Join(ErrParsingTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.address, err)) + } + // update balances + p.balancesMtx.Lock() + if toBalance, ok := p.balances[logData.To]; ok { + p.balances[logData.To] = new(big.Int).Add(toBalance, logData.Value) + } else { + p.balances[logData.To] = logData.Value + } + if fromBalance, ok := p.balances[logData.From]; ok { + p.balances[logData.From] = new(big.Int).Sub(fromBalance, logData.Value) + } else { + p.balances[logData.From] = new(big.Int).Neg(logData.Value) } + p.balancesMtx.Unlock() } p.balancesMtx.RLock() finalHolders := len(p.balances) p.balancesMtx.RUnlock() log.Infow("saving blocks", "count", finalHolders-initialHolders, - "logs", logCount, - "blocks/s", 1000*float32(fromBlock-initialBlock)/float32(time.Since(startTime).Milliseconds()), + "logs", len(logs), + "blocks/s", 1000*float32(lastBlock-fromBlock)/float32(time.Since(startTime).Milliseconds()), "took", time.Since(startTime).Seconds(), "progress", fmt.Sprintf("%d%%", (fromBlock*100)/toBlock)) - return p.balances, lastBlock, true, nil + return p.balances, newTransfers, lastBlock, synced, nil } func (p *ERC20HolderProvider) Close() error { @@ -277,6 +232,7 @@ func (p *ERC20HolderProvider) BalanceAt(ctx context.Context, addr common.Address } func (p *ERC20HolderProvider) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) { + internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetUint64(blockNumber)) if err != nil { return "", err @@ -285,6 +241,7 @@ func (p *ERC20HolderProvider) BlockTimestamp(ctx context.Context, blockNumber ui } func (p *ERC20HolderProvider) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) { + internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) if err != nil { return nil, err @@ -293,6 +250,7 @@ func (p *ERC20HolderProvider) BlockRootHash(ctx context.Context, blockNumber uin } func (p *ERC20HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) (uint64, error) { + internal.GetBlockByNumberCounter.Add(1) lastBlockHeader, err := p.client.HeaderByNumber(ctx, nil) if err != nil { return 0, err diff --git a/scanner/providers/web3/erc721_provider.go b/scanner/providers/web3/erc721_provider.go new file mode 100644 index 00000000..eead600a --- /dev/null +++ b/scanner/providers/web3/erc721_provider.go @@ -0,0 +1,265 @@ +package web3 + +import ( + "context" + "errors" + "fmt" + "math/big" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + erc721 "github.com/vocdoni/census3/contracts/erc/erc721" + "github.com/vocdoni/census3/internal" + "github.com/vocdoni/census3/scanner/providers" + "go.vocdoni.io/dvote/log" +) + +type ERC721HolderProvider struct { + endpoints NetworkEndpoints + client *ethclient.Client + + contract *erc721.ERC721Contract + address common.Address + chainID uint64 + name string + symbol string + decimals uint64 + totalSupply *big.Int + creationBlock uint64 + + balances map[common.Address]*big.Int + balancesMtx sync.RWMutex + balancesBlock uint64 +} + +func (p *ERC721HolderProvider) Init(iconf any) error { + // parse the config and set the endpoints + conf, ok := iconf.(Web3ProviderConfig) + if !ok { + return errors.New("invalid config type, it must be Web3ProviderConfig") + } + p.endpoints = conf.Endpoints + // reset the internal balances + p.balances = make(map[common.Address]*big.Int) + p.balancesMtx = sync.RWMutex{} + // set the reference if the address and chainID are defined in the config + if conf.HexAddress != "" && conf.ChainID > 0 { + return p.SetRef(Web3ProviderRef{ + HexAddress: conf.HexAddress, + ChainID: conf.ChainID, + }) + } + return nil +} + +func (p *ERC721HolderProvider) SetRef(iref any) error { + if p.endpoints == nil { + return errors.New("endpoints not defined") + } + ref, ok := iref.(Web3ProviderRef) + if !ok { + return errors.New("invalid ref type, it must be Web3ProviderRef") + } + currentEndpoint, exists := p.endpoints.EndpointByChainID(ref.ChainID) + if !exists { + return errors.New("endpoint not found for the given chainID") + } + // connect to the endpoint + client, err := currentEndpoint.GetClient(DefaultMaxWeb3ClientRetries) + if err != nil { + return errors.Join(ErrConnectingToWeb3Client, fmt.Errorf("[ERC721] %s: %w", ref.HexAddress, err)) + } + // set the client, parse the address and initialize the contract + p.client = client + address := common.HexToAddress(ref.HexAddress) + if p.contract, err = erc721.NewERC721Contract(address, client); err != nil { + return errors.Join(ErrInitializingContract, fmt.Errorf("[ERC721] %s: %w", p.address, err)) + } + // reset the internal attributes + p.address = address + p.chainID = ref.ChainID + p.name = "" + p.symbol = "" + p.decimals = 0 + p.totalSupply = nil + p.creationBlock = 0 + // reset balances + p.balancesMtx.Lock() + defer p.balancesMtx.Unlock() + p.balances = make(map[common.Address]*big.Int) + p.balancesBlock = 0 + return nil +} + +func (p *ERC721HolderProvider) SetLastBalances(ctx context.Context, id []byte, + balances map[common.Address]*big.Int, from uint64, +) error { + p.balancesMtx.Lock() + defer p.balancesMtx.Unlock() + + if from < p.balancesBlock { + return errors.New("from block is lower than the last block analyzed") + } + p.balancesBlock = from + p.balances = balances + return nil +} + +func (p *ERC721HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fromBlock uint64) ( + map[common.Address]*big.Int, uint64, uint64, bool, error, +) { + // calculate the range of blocks to scan, by default take the last block + // scanned and scan to the latest block + toBlock, err := p.LatestBlockNumber(ctx, nil) + if err != nil { + return nil, 0, fromBlock, false, err + } + log.Infow("scan iteration", + "address", p.address, + "type", providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC721], + "from", fromBlock, + "to", toBlock) + // some variables to calculate the progress + startTime := time.Now() + p.balancesMtx.RLock() + initialHolders := len(p.balances) + p.balancesMtx.RUnlock() + // iterate scanning the logs in the range of blocks until the last block + // is reached + logs, lastBlock, synced, err := rangeOfLogs(ctx, p.client, p.address, fromBlock, toBlock, LOG_TOPIC_ERC20_TRANSFER) + if err != nil { + return nil, 0, fromBlock, false, err + } + // encode the number of new transfers + newTransfers := uint64(len(logs)) + // iterate the logs and update the balances + for _, currentLog := range logs { + logData, err := p.contract.ERC721ContractFilterer.ParseTransfer(currentLog) + if err != nil { + return nil, newTransfers, lastBlock, false, fmt.Errorf("[ERC721] %w: %s: %w", ErrParsingTokenLogs, p.address.Hex(), err) + } + // update balances + p.balancesMtx.Lock() + if toBalance, ok := p.balances[logData.To]; ok { + p.balances[logData.To] = new(big.Int).Add(toBalance, big.NewInt(1)) + } else { + p.balances[logData.To] = big.NewInt(1) + } + if fromBalance, ok := p.balances[logData.From]; ok { + p.balances[logData.From] = new(big.Int).Sub(fromBalance, big.NewInt(1)) + } else { + p.balances[logData.From] = big.NewInt(-1) + } + p.balancesMtx.Unlock() + } + p.balancesMtx.RLock() + finalHolders := len(p.balances) + p.balancesMtx.RUnlock() + log.Infow("saving blocks", + "count", finalHolders-initialHolders, + "logs", len(logs), + "blocks/s", 1000*float32(lastBlock-fromBlock)/float32(time.Since(startTime).Milliseconds()), + "took", time.Since(startTime).Seconds(), + "progress", fmt.Sprintf("%d%%", (fromBlock*100)/toBlock)) + return p.balances, newTransfers, lastBlock, synced, nil +} + +func (p *ERC721HolderProvider) Close() error { + return nil +} + +func (p *ERC721HolderProvider) IsExternal() bool { + return false +} + +func (p *ERC721HolderProvider) Address() common.Address { + return p.address +} + +func (p *ERC721HolderProvider) Type() uint64 { + return providers.CONTRACT_TYPE_ERC721 +} + +func (p *ERC721HolderProvider) ChainID() uint64 { + return p.chainID +} + +func (p *ERC721HolderProvider) Name(_ []byte) (string, error) { + var err error + if p.name == "" { + p.name, err = p.contract.ERC721ContractCaller.Name(nil) + } + return p.name, err +} + +func (p *ERC721HolderProvider) Symbol(_ []byte) (string, error) { + var err error + if p.symbol == "" { + p.symbol, err = p.contract.ERC721ContractCaller.Symbol(nil) + } + return p.symbol, err +} + +func (p *ERC721HolderProvider) Decimals(_ []byte) (uint64, error) { + return 0, nil +} + +func (p *ERC721HolderProvider) TotalSupply(_ []byte) (*big.Int, error) { + return nil, nil +} + +func (p *ERC721HolderProvider) BalanceOf(addr common.Address, _ []byte) (*big.Int, error) { + return p.contract.ERC721ContractCaller.BalanceOf(nil, addr) +} + +func (p *ERC721HolderProvider) BalanceAt(ctx context.Context, addr common.Address, + _ []byte, blockNumber uint64, +) (*big.Int, error) { + return p.client.BalanceAt(ctx, addr, new(big.Int).SetUint64(blockNumber)) +} + +func (p *ERC721HolderProvider) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) { + internal.GetBlockByNumberCounter.Add(1) + blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetUint64(blockNumber)) + if err != nil { + return "", err + } + return time.Unix(int64(blockHeader.Time), 0).Format(timeLayout), nil +} + +func (p *ERC721HolderProvider) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) { + internal.GetBlockByNumberCounter.Add(1) + blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) + if err != nil { + return nil, err + } + return blockHeader.Root.Bytes(), nil +} + +func (p *ERC721HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) (uint64, error) { + internal.GetBlockByNumberCounter.Add(1) + lastBlockHeader, err := p.client.HeaderByNumber(ctx, nil) + if err != nil { + return 0, err + } + return lastBlockHeader.Number.Uint64(), nil +} + +func (p *ERC721HolderProvider) CreationBlock(ctx context.Context, _ []byte) (uint64, error) { + var err error + if p.creationBlock == 0 { + var lastBlock uint64 + lastBlock, err = p.LatestBlockNumber(ctx, nil) + if err != nil { + return 0, err + } + p.creationBlock, err = creationBlockInRange(p.client, ctx, p.address, 0, lastBlock) + } + return p.creationBlock, err +} + +func (p *ERC721HolderProvider) IconURI(_ []byte) (string, error) { + return "", nil +} diff --git a/scanner/providers/web3/erc777_provider.go b/scanner/providers/web3/erc777_provider.go new file mode 100644 index 00000000..5c84c8c3 --- /dev/null +++ b/scanner/providers/web3/erc777_provider.go @@ -0,0 +1,265 @@ +package web3 + +import ( + "context" + "errors" + "fmt" + "math/big" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + erc777 "github.com/vocdoni/census3/contracts/erc/erc777" + "github.com/vocdoni/census3/internal" + "github.com/vocdoni/census3/scanner/providers" + "go.vocdoni.io/dvote/log" +) + +type ERC777HolderProvider struct { + endpoints NetworkEndpoints + client *ethclient.Client + + contract *erc777.ERC777Contract + address common.Address + chainID uint64 + name string + symbol string + decimals uint64 + totalSupply *big.Int + creationBlock uint64 + + balances map[common.Address]*big.Int + balancesMtx sync.RWMutex + balancesBlock uint64 +} + +func (p *ERC777HolderProvider) Init(iconf any) error { + // parse the config and set the endpoints + conf, ok := iconf.(Web3ProviderConfig) + if !ok { + return errors.New("invalid config type, it must be Web3ProviderConfig") + } + p.endpoints = conf.Endpoints + // reset the internal balances + p.balances = make(map[common.Address]*big.Int) + p.balancesMtx = sync.RWMutex{} + // set the reference if the address and chainID are defined in the config + if conf.HexAddress != "" && conf.ChainID > 0 { + return p.SetRef(Web3ProviderRef{ + HexAddress: conf.HexAddress, + ChainID: conf.ChainID, + }) + } + return nil +} + +func (p *ERC777HolderProvider) SetRef(iref any) error { + if p.endpoints == nil { + return errors.New("endpoints not defined") + } + ref, ok := iref.(Web3ProviderRef) + if !ok { + return errors.New("invalid ref type, it must be Web3ProviderRef") + } + currentEndpoint, exists := p.endpoints.EndpointByChainID(ref.ChainID) + if !exists { + return errors.New("endpoint not found for the given chainID") + } + // connect to the endpoint + client, err := currentEndpoint.GetClient(DefaultMaxWeb3ClientRetries) + if err != nil { + return errors.Join(ErrConnectingToWeb3Client, fmt.Errorf("[ERC777] %s: %w", ref.HexAddress, err)) + } + // set the client, parse the address and initialize the contract + p.client = client + address := common.HexToAddress(ref.HexAddress) + if p.contract, err = erc777.NewERC777Contract(address, client); err != nil { + return errors.Join(ErrInitializingContract, fmt.Errorf("[ERC777] %s: %w", p.address, err)) + } + // reset the internal attributes + p.address = address + p.chainID = ref.ChainID + p.name = "" + p.symbol = "" + p.decimals = 0 + p.totalSupply = nil + p.creationBlock = 0 + // reset balances + p.balancesMtx.Lock() + defer p.balancesMtx.Unlock() + p.balances = make(map[common.Address]*big.Int) + p.balancesBlock = 0 + return nil +} + +func (p *ERC777HolderProvider) SetLastBalances(ctx context.Context, id []byte, + balances map[common.Address]*big.Int, from uint64, +) error { + p.balancesMtx.Lock() + defer p.balancesMtx.Unlock() + + if from < p.balancesBlock { + return errors.New("from block is lower than the last block analyzed") + } + p.balancesBlock = from + p.balances = balances + return nil +} + +func (p *ERC777HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fromBlock uint64) ( + map[common.Address]*big.Int, uint64, uint64, bool, error, +) { + // calculate the range of blocks to scan, by default take the last block + // scanned and scan to the latest block + toBlock, err := p.LatestBlockNumber(ctx, nil) + if err != nil { + return nil, 0, fromBlock, false, err + } + log.Infow("scan iteration", + "address", p.address, + "type", providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC777], + "from", fromBlock, + "to", toBlock) + // some variables to calculate the progress + startTime := time.Now() + p.balancesMtx.RLock() + initialHolders := len(p.balances) + p.balancesMtx.RUnlock() + // iterate scanning the logs in the range of blocks until the last block + // is reached + logs, lastBlock, synced, err := rangeOfLogs(ctx, p.client, p.address, fromBlock, toBlock, LOG_TOPIC_ERC20_TRANSFER) + if err != nil { + return nil, 0, fromBlock, false, err + } + // encode the number of new transfers + newTransfers := uint64(len(logs)) + // iterate the logs and update the balances + for _, currentLog := range logs { + logData, err := p.contract.ERC777ContractFilterer.ParseTransfer(currentLog) + if err != nil { + return nil, newTransfers, lastBlock, false, errors.Join(ErrParsingTokenLogs, fmt.Errorf("[ERC777] %s: %w", p.address, err)) + } + // update balances + p.balancesMtx.Lock() + if toBalance, ok := p.balances[logData.To]; ok { + p.balances[logData.To] = new(big.Int).Add(toBalance, big.NewInt(1)) + } else { + p.balances[logData.To] = big.NewInt(1) + } + if fromBalance, ok := p.balances[logData.From]; ok { + p.balances[logData.From] = new(big.Int).Sub(fromBalance, big.NewInt(1)) + } else { + p.balances[logData.From] = big.NewInt(-1) + } + p.balancesMtx.Unlock() + } + p.balancesMtx.RLock() + finalHolders := len(p.balances) + p.balancesMtx.RUnlock() + log.Infow("saving blocks", + "count", finalHolders-initialHolders, + "logs", len(logs), + "blocks/s", 1000*float32(lastBlock-fromBlock)/float32(time.Since(startTime).Milliseconds()), + "took", time.Since(startTime).Seconds(), + "progress", fmt.Sprintf("%d%%", (fromBlock*100)/toBlock)) + return p.balances, newTransfers, lastBlock, synced, nil +} + +func (p *ERC777HolderProvider) Close() error { + return nil +} + +func (p *ERC777HolderProvider) IsExternal() bool { + return false +} + +func (p *ERC777HolderProvider) Address() common.Address { + return p.address +} + +func (p *ERC777HolderProvider) Type() uint64 { + return providers.CONTRACT_TYPE_ERC777 +} + +func (p *ERC777HolderProvider) ChainID() uint64 { + return p.chainID +} + +func (p *ERC777HolderProvider) Name(_ []byte) (string, error) { + var err error + if p.name == "" { + p.name, err = p.contract.ERC777ContractCaller.Name(nil) + } + return p.name, err +} + +func (p *ERC777HolderProvider) Symbol(_ []byte) (string, error) { + var err error + if p.symbol == "" { + p.symbol, err = p.contract.ERC777ContractCaller.Symbol(nil) + } + return p.symbol, err +} + +func (p *ERC777HolderProvider) Decimals(_ []byte) (uint64, error) { + return 0, nil +} + +func (p *ERC777HolderProvider) TotalSupply(_ []byte) (*big.Int, error) { + return nil, nil +} + +func (p *ERC777HolderProvider) BalanceOf(addr common.Address, _ []byte) (*big.Int, error) { + return p.contract.ERC777ContractCaller.BalanceOf(nil, addr) +} + +func (p *ERC777HolderProvider) BalanceAt(ctx context.Context, addr common.Address, + _ []byte, blockNumber uint64, +) (*big.Int, error) { + return p.client.BalanceAt(ctx, addr, new(big.Int).SetUint64(blockNumber)) +} + +func (p *ERC777HolderProvider) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) { + internal.GetBlockByNumberCounter.Add(1) + blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetUint64(blockNumber)) + if err != nil { + return "", err + } + return time.Unix(int64(blockHeader.Time), 0).Format(timeLayout), nil +} + +func (p *ERC777HolderProvider) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) { + internal.GetBlockByNumberCounter.Add(1) + blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) + if err != nil { + return nil, err + } + return blockHeader.Root.Bytes(), nil +} + +func (p *ERC777HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) (uint64, error) { + internal.GetBlockByNumberCounter.Add(1) + lastBlockHeader, err := p.client.HeaderByNumber(ctx, nil) + if err != nil { + return 0, err + } + return lastBlockHeader.Number.Uint64(), nil +} + +func (p *ERC777HolderProvider) CreationBlock(ctx context.Context, _ []byte) (uint64, error) { + var err error + if p.creationBlock == 0 { + var lastBlock uint64 + lastBlock, err = p.LatestBlockNumber(ctx, nil) + if err != nil { + return 0, err + } + p.creationBlock, err = creationBlockInRange(p.client, ctx, p.address, 0, lastBlock) + } + return p.creationBlock, err +} + +func (p *ERC777HolderProvider) IconURI(_ []byte) (string, error) { + return "", nil +} diff --git a/scanner/providers/web3/helpers.go b/scanner/providers/web3/helpers.go deleted file mode 100644 index 15881e86..00000000 --- a/scanner/providers/web3/helpers.go +++ /dev/null @@ -1,50 +0,0 @@ -package web3 - -import ( - "context" - "fmt" - "math/big" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/vocdoni/census3/scanner/providers" -) - -func TokenTypeFromString(s string) uint64 { - if c, ok := providers.TokenTypeIntMap[s]; ok { - return c - } - return providers.CONTRACT_TYPE_UNKNOWN -} - -// creationBlockInRange function finds the block number of a contract between -// the bounds provided as start and end blocks. -func creationBlockInRange(client *ethclient.Client, ctx context.Context, addr common.Address, start, end uint64) (uint64, error) { - // if both block numbers are equal, return its value as birthblock - if start == end { - return start, nil - } - // find the middle block between start and end blocks and get the contract - // code at this block - midBlock := (start + end) / 2 - codeLen, err := sourceCodeLenAt(client, ctx, addr, midBlock) - if err != nil && !strings.Contains(err.Error(), fmt.Sprintf("No state available for block %d", midBlock)) { - return 0, err - } - // if any code is found, keep trying with the lower half of blocks until - // find the first. if not, keep trying with the upper half - if codeLen > 2 { - return creationBlockInRange(client, ctx, addr, start, midBlock) - } else { - return creationBlockInRange(client, ctx, addr, midBlock+1, end) - } -} - -// SourceCodeLenAt function returns the length of the current contract bytecode -// at the block number provided. -func sourceCodeLenAt(client *ethclient.Client, ctx context.Context, addr common.Address, atBlockNumber uint64) (int, error) { - blockNumber := new(big.Int).SetUint64(atBlockNumber) - sourceCode, err := client.CodeAt(ctx, addr, blockNumber) - return len(sourceCode), err -} diff --git a/scanner/providers/web3/web3_provider.go b/scanner/providers/web3/web3_provider.go index a7a51c20..ccd6b38a 100644 --- a/scanner/providers/web3/web3_provider.go +++ b/scanner/providers/web3/web3_provider.go @@ -1,5 +1,20 @@ package web3 +import ( + "context" + "errors" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/vocdoni/census3/scanner/providers" + "go.vocdoni.io/dvote/log" +) + type Web3ProviderRef struct { HexAddress string ChainID uint64 @@ -9,3 +24,122 @@ type Web3ProviderConfig struct { Web3ProviderRef Endpoints NetworkEndpoints } + +// TokenTypeFromString function returns the token type ID from a string value. +// If the string is not recognized, it returns CONTRACT_TYPE_UNKNOWN. +func TokenTypeFromString(s string) uint64 { + if c, ok := providers.TokenTypeIntMap[s]; ok { + return c + } + return providers.CONTRACT_TYPE_UNKNOWN +} + +// creationBlockInRange function finds the block number of a contract between +// the bounds provided as start and end blocks. +func creationBlockInRange(client *ethclient.Client, ctx context.Context, addr common.Address, start, end uint64) (uint64, error) { + // if both block numbers are equal, return its value as birthblock + if start == end { + return start, nil + } + // find the middle block between start and end blocks and get the contract + // code at this block + midBlock := (start + end) / 2 + codeLen, err := sourceCodeLenAt(client, ctx, addr, midBlock) + if err != nil && !strings.Contains(err.Error(), fmt.Sprintf("No state available for block %d", midBlock)) { + return 0, err + } + // if any code is found, keep trying with the lower half of blocks until + // find the first. if not, keep trying with the upper half + if codeLen > 2 { + return creationBlockInRange(client, ctx, addr, start, midBlock) + } else { + return creationBlockInRange(client, ctx, addr, midBlock+1, end) + } +} + +// SourceCodeLenAt function returns the length of the current contract bytecode +// at the block number provided. +func sourceCodeLenAt(client *ethclient.Client, ctx context.Context, addr common.Address, atBlockNumber uint64) (int, error) { + blockNumber := new(big.Int).SetUint64(atBlockNumber) + sourceCode, err := client.CodeAt(ctx, addr, blockNumber) + return len(sourceCode), err +} + +// rangeOfLogs function returns the logs of a token contract between the +// provided block numbers. It returns the logs, the last block scanned and an +// error if any. It filters the logs by the topic hash and for the token +// contract address provided. +func rangeOfLogs(ctx context.Context, client *ethclient.Client, addr common.Address, + fromBlock, lastBlock uint64, hexTopics ...string, +) ([]types.Log, uint64, bool, error) { + // if the range is too big, scan only a part of it using the constant + // BLOCKS_TO_SCAN_AT_ONCE + initialLastBlock := lastBlock + if lastBlock-fromBlock > BLOCKS_TO_SCAN_AT_ONCE { + lastBlock = fromBlock + MAX_SCAN_BLOCKS_PER_ITERATION + } + if fromBlock > lastBlock { + fromBlock = lastBlock + } + // some variables to calculate the end of the scan and store the logs + logCount := 0 + finalLogs := []types.Log{} + blocksRange := BLOCKS_TO_SCAN_AT_ONCE + topicHashes := make([]common.Hash, len(hexTopics)) + for i, topic := range hexTopics { + topicHashes[i] = common.HexToHash(topic) + } + for fromBlock < lastBlock { + select { + case <-ctx.Done(): + log.Warnf("scan graceful canceled by context") + return finalLogs, fromBlock, false, nil + default: + if logCount > MAX_SCAN_LOGS_PER_ITERATION { + return finalLogs, fromBlock, false, nil + } + log.Debugw("scanning logs", + "address", addr.Hex(), + "fromBlock", fromBlock, + "toBlock", fromBlock+blocksRange-1) + // compose the filter to get the logs of the ERC20 Transfer events + filter := ethereum.FilterQuery{ + Addresses: []common.Address{addr}, + FromBlock: new(big.Int).SetUint64(fromBlock), + ToBlock: new(big.Int).SetUint64(fromBlock + blocksRange - 1), + Topics: [][]common.Hash{topicHashes}, + } + // get the logs and check if there are any errors + logs, err := client.FilterLogs(ctx, filter) + if err != nil { + // if the error is about the query returning more than the maximum + // allowed logs, split the range of blocks in half and try again + if strings.Contains(err.Error(), "query returned more than") { + blocksRange /= 2 + log.Warnf("too much results on query, decreasing blocks to %d", blocksRange) + continue + } + return finalLogs, fromBlock, false, errors.Join(ErrScanningTokenLogs, fmt.Errorf("%s: %w", addr.Hex(), err)) + } + // if there are logs, add them to the final list and update the + // counter + if len(logs) > 0 { + finalLogs = append(finalLogs, logs...) + logCount += len(logs) + } + // update the fromBlock to the last block scanned + fromBlock += blocksRange + } + } + synced := fromBlock >= initialLastBlock + lastSyncedBlock := initialLastBlock + if !synced { + lastSyncedBlock = uint64(0) + for _, l := range finalLogs { + if l.BlockNumber > lastSyncedBlock { + lastSyncedBlock = l.BlockNumber + 1 + } + } + } + return finalLogs, lastSyncedBlock, synced, nil +} diff --git a/scanner/scanner.go b/scanner/scanner.go index f6fba46d..8b73c830 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/vocdoni/census3/db" queries "github.com/vocdoni/census3/db/sqlc" + "github.com/vocdoni/census3/internal" "github.com/vocdoni/census3/scanner/providers" "github.com/vocdoni/census3/scanner/providers/web3" "go.vocdoni.io/dvote/log" @@ -49,13 +50,11 @@ type Scanner struct { // NewScanner returns a new scanner instance with the required parameters // initialized. -func NewScanner(db *db.DB, networks web3.NetworkEndpoints, - providers map[uint64]providers.HolderProvider, coolDown time.Duration, -) *Scanner { +func NewScanner(db *db.DB, networks web3.NetworkEndpoints, coolDown time.Duration) *Scanner { return &Scanner{ db: db, networks: networks, - providers: providers, + providers: make(map[uint64]providers.HolderProvider), coolDown: coolDown, tokens: []*ScannerToken{}, tokensMtx: sync.Mutex{}, @@ -63,6 +62,14 @@ func NewScanner(db *db.DB, networks web3.NetworkEndpoints, } } +// SetProviders sets the providers that the scanner will use to get the holders +// of the tokens. +func (s *Scanner) SetProviders(newProviders ...providers.HolderProvider) { + for _, provider := range newProviders { + s.providers[provider.Type()] = provider + } +} + // Start starts the scanner. It starts a loop that scans the tokens in the // database and saves the holders in the database. It stops when the context is // cancelled. @@ -83,7 +90,13 @@ func (s *Scanner) Start(ctx context.Context) { } atSyncGlobal := true for _, token := range tokens { - holders, lastBlock, synced, err := s.ScanHolders(ctx, token) + log.Infow("scanning token", + "address", token.Address.Hex(), + "chainID", token.ChainID, + "externalID", token.ExternalID, + "lastBlock", token.LastBlock, + "ready", token.Ready) + holders, newTransfers, lastBlock, synced, err := s.ScanHolders(ctx, token) if err != nil { log.Error(err) continue @@ -91,20 +104,19 @@ func (s *Scanner) Start(ctx context.Context) { if !synced { atSyncGlobal = false } - if len(holders) > 0 { - s.waiter.Add(1) - go func(t *ScannerToken, h map[common.Address]*big.Int, lb uint64, sy bool) { - defer s.waiter.Done() - if err = s.SaveHolders(ctx, t, h, lb, sy); err != nil { - log.Error(err) - } - }(token, holders, lastBlock, synced) - } + s.waiter.Add(1) + go func(t *ScannerToken, h map[common.Address]*big.Int, n, lb uint64, sy bool) { + defer s.waiter.Done() + if err = s.SaveHolders(ctx, t, h, n, lb, sy); err != nil { + log.Error(err) + } + }(token, holders, newTransfers, lastBlock, synced) } log.Infow("scan iteration finished", "iteration", itCounter, "duration", time.Since(startTime).Seconds(), "atSync", atSyncGlobal) + log.Debugf("GetBlockByNumberCounter: %d", internal.GetBlockByNumberCounter.Load()) if atSyncGlobal { time.Sleep(s.coolDown) } else { @@ -118,6 +130,11 @@ func (s *Scanner) Start(ctx context.Context) { // finish. func (s *Scanner) Stop() { s.cancel() + for _, provider := range s.providers { + if err := provider.Close(); err != nil { + log.Error(err) + } + } s.waiter.Wait() } @@ -130,108 +147,77 @@ func (s *Scanner) Stop() { func (s *Scanner) TokensToScan(ctx context.Context) ([]*ScannerToken, error) { internalCtx, cancel := context.WithTimeout(ctx, SCAN_TIMEOUT) defer cancel() - // create a tx to use it in the following queries - tx, err := s.db.RW.BeginTx(internalCtx, nil) - if err != nil { - return nil, err - } - defer func() { - if err := tx.Rollback(); err != nil && !errors.Is(sql.ErrTxDone, err) { - log.Error(err) - return - } - }() - qtx := s.db.QueriesRW.WithTx(tx) - tokens := []*ScannerToken{} // get last created tokens from the database to scan them first - lastNotSyncedTokens, err := qtx.ListLastNoSyncedTokens(ctx) + lastNotSyncedTokens, err := s.db.QueriesRO.ListLastNoSyncedTokens(internalCtx) if err != nil && !errors.Is(sql.ErrNoRows, err) { return nil, err } // parse last not synced token addresses for _, token := range lastNotSyncedTokens { - lastBlock := uint64(token.CreationBlock) - if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil { - lastBlock = blockNumber - } tokens = append(tokens, &ScannerToken{ Address: common.BytesToAddress(token.ID), ChainID: token.ChainID, Type: token.TypeID, ExternalID: token.ExternalID, - LastBlock: lastBlock, - Ready: token.CreationBlock > 0, + LastBlock: uint64(token.LastBlock), + Ready: token.CreationBlock > 0 && token.LastBlock >= token.CreationBlock, Synced: token.Synced, }) } // get old tokens from the database - oldNotSyncedTokens, err := qtx.ListOldNoSyncedTokens(ctx) + oldNotSyncedTokens, err := s.db.QueriesRO.ListOldNoSyncedTokens(internalCtx) if err != nil && !errors.Is(sql.ErrNoRows, err) { return nil, err } - // get the current block number of every chain - currentBlockNumbers, err := s.networks.CurrentBlockNumbers(ctx) - if err != nil { - return nil, err - } - // sort old not synced tokens by nearest to be synced, that is, the tokens - // that have the minimum difference between the current block of its chain - // and the last block scanned by the scanner (retrieved from the database - // as LastBlock) - sort.Slice(oldNotSyncedTokens, func(i, j int) bool { - iLastBlock := uint64(oldNotSyncedTokens[i].CreationBlock) - if oldNotSyncedTokens[i].LastBlock != nil { - iLastBlock = uint64(oldNotSyncedTokens[i].LastBlock.(int64)) - } - jLastBlock := uint64(oldNotSyncedTokens[j].CreationBlock) - if oldNotSyncedTokens[j].LastBlock != nil { - jLastBlock = uint64(oldNotSyncedTokens[j].LastBlock.(int64)) - } - iBlocksReamining := currentBlockNumbers[oldNotSyncedTokens[i].ChainID] - uint64(iLastBlock) - jBlocksReamining := currentBlockNumbers[oldNotSyncedTokens[j].ChainID] - uint64(jLastBlock) - return iBlocksReamining < jBlocksReamining - }) - // parse old not synced token addresses - for _, token := range oldNotSyncedTokens { - lastBlock := uint64(token.CreationBlock) - if token.LastBlock != nil { - lastBlock = uint64(token.LastBlock.(int64)) + // if there are old not synced tokens, sort them by nearest to be synced + // and parse them, if not, continue to avoid web3 calls + if len(oldNotSyncedTokens) > 0 { + // get the current block number of every chain + currentBlockNumbers, err := s.networks.CurrentBlockNumbers(internalCtx) + if err != nil { + return nil, err } - tokens = append(tokens, &ScannerToken{ - Address: common.BytesToAddress(token.ID), - ChainID: token.ChainID, - Type: token.TypeID, - ExternalID: token.ExternalID, - LastBlock: lastBlock, - Ready: token.CreationBlock > 0, - Synced: token.Synced, + // sort old not synced tokens by nearest to be synced, that is, the tokens + // that have the minimum difference between the current block of its chain + // and the last block scanned by the scanner (retrieved from the database + // as LastBlock) + sort.Slice(oldNotSyncedTokens, func(i, j int) bool { + iBlocksReamining := currentBlockNumbers[oldNotSyncedTokens[i].ChainID] - + uint64(oldNotSyncedTokens[i].LastBlock) + jBlocksReamining := currentBlockNumbers[oldNotSyncedTokens[j].ChainID] - + uint64(oldNotSyncedTokens[j].LastBlock) + return iBlocksReamining < jBlocksReamining }) + // parse old not synced token addresses + for _, token := range oldNotSyncedTokens { + tokens = append(tokens, &ScannerToken{ + Address: common.BytesToAddress(token.ID), + ChainID: token.ChainID, + Type: token.TypeID, + ExternalID: token.ExternalID, + LastBlock: uint64(token.LastBlock), + Ready: token.CreationBlock > 0 && token.LastBlock >= token.CreationBlock, + Synced: token.Synced, + }) + } } // get last created tokens from the database to scan them first - syncedTokens, err := qtx.ListSyncedTokens(ctx) + syncedTokens, err := s.db.QueriesRO.ListSyncedTokens(internalCtx) if err != nil && !errors.Is(sql.ErrNoRows, err) { return nil, err } for _, token := range syncedTokens { - lastBlock := uint64(token.CreationBlock) - if blockNumber, err := s.db.QueriesRO.LastBlockByTokenID(ctx, token.ID); err == nil { - lastBlock = blockNumber - } - s.tokens = append(s.tokens, &ScannerToken{ + tokens = append(tokens, &ScannerToken{ Address: common.BytesToAddress(token.ID), ChainID: token.ChainID, Type: token.TypeID, ExternalID: token.ExternalID, - LastBlock: lastBlock, - Ready: token.CreationBlock > 0, + LastBlock: uint64(token.LastBlock), + Ready: token.CreationBlock > 0 && token.LastBlock >= token.CreationBlock, Synced: token.Synced, }) } - // close the database tx and commit it - if err := tx.Commit(); err != nil { - return nil, err - } // update the tokens to scan in the scanner and return them s.tokensMtx.Lock() s.tokens = tokens @@ -243,22 +229,25 @@ func (s *Scanner) TokensToScan(ctx context.Context) ([]*ScannerToken, error) { // from the database, set them into the provider and get the new ones. It // returns the new holders, the last block scanned and if the token is synced // after the scan. -func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) (map[common.Address]*big.Int, uint64, bool, error) { +func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) ( + map[common.Address]*big.Int, uint64, uint64, bool, error, +) { log.Infow("scanning holders", "address", token.Address.Hex(), "chainID", token.ChainID, - "externalID", token.ExternalID) + "externalID", token.ExternalID, + "lastBlock", token.LastBlock) internalCtx, cancel := context.WithTimeout(ctx, SCAN_TIMEOUT) defer cancel() // get the correct token holder for the current token - provider, exists := s.providers[token.ChainID] + provider, exists := s.providers[token.Type] if !exists { - return nil, token.LastBlock, token.Synced, fmt.Errorf("no provider for chain %d", token.ChainID) + return nil, 0, token.LastBlock, token.Synced, fmt.Errorf("token type %d not supported", token.Type) } // create a tx to use it in the following queries tx, err := s.db.RW.BeginTx(internalCtx, nil) if err != nil { - return nil, token.LastBlock, token.Synced, err + return nil, 0, token.LastBlock, token.Synced, err } defer func() { if err := tx.Rollback(); err != nil && !errors.Is(sql.ErrTxDone, err) { @@ -272,27 +261,32 @@ func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) (map[com HexAddress: token.Address.Hex(), ChainID: token.ChainID, }); err != nil { - return nil, token.LastBlock, token.Synced, err + return nil, 0, token.LastBlock, token.Synced, err } // if the token is not ready yet (its creation block has not been // calculated yet), calculate it, update the token information and // return if !token.Ready { + log.Debugw("token not ready yet, calculating creation block and continue", + "address", token.Address.Hex(), + "chainID", token.ChainID, + "externalID", token.ExternalID) creationBlock, err := provider.CreationBlock(internalCtx, []byte(token.ExternalID)) if err != nil { - return nil, token.LastBlock, token.Synced, err + return nil, 0, token.LastBlock, token.Synced, err } - _, err = qtx.UpdateTokenCreationBlock(internalCtx, queries.UpdateTokenCreationBlockParams{ + _, err = qtx.UpdateTokenBlocks(internalCtx, queries.UpdateTokenBlocksParams{ ID: token.Address.Bytes(), ChainID: token.ChainID, ExternalID: token.ExternalID, CreationBlock: int64(creationBlock), + LastBlock: int64(creationBlock), }) if err != nil { - return nil, token.LastBlock, token.Synced, err + return nil, 0, token.LastBlock, token.Synced, err } // close the database tx and commit it - return nil, token.LastBlock, token.Synced, tx.Commit() + return nil, 0, creationBlock, token.Synced, tx.Commit() } } // get the current token holders from the database @@ -303,7 +297,7 @@ func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) (map[com ExternalID: token.ExternalID, }) if err != nil { - return nil, token.LastBlock, token.Synced, err + return nil, 0, token.LastBlock, token.Synced, err } currentHolders := map[common.Address]*big.Int{} for _, result := range results { @@ -311,11 +305,11 @@ func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) (map[com } // close the database tx and commit it if err := tx.Commit(); err != nil { - return nil, token.LastBlock, token.Synced, err + return nil, 0, token.LastBlock, token.Synced, err } // set the current holders into the provider and get the new ones if err := provider.SetLastBalances(ctx, []byte(token.ExternalID), currentHolders, token.LastBlock); err != nil { - return nil, token.LastBlock, token.Synced, err + return nil, 0, token.LastBlock, token.Synced, err } return provider.HoldersBalances(ctx, []byte(token.ExternalID), token.LastBlock) } @@ -325,9 +319,10 @@ func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) (map[com // updates or deletes the token holders in the database depending on the // calculated balance. func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, - holders map[common.Address]*big.Int, lastBlock uint64, synced bool, + holders map[common.Address]*big.Int, newTransfers, lastBlock uint64, + synced bool, ) error { - log.Debugw("saving token holders", + log.Debugw("saving token status and holders", "token", token.Address.Hex(), "chainID", token.ChainID, "externalID", token.ExternalID, @@ -357,7 +352,6 @@ func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, } }() qtx := s.db.QueriesRW.WithTx(tx) - // get the current token information from the database tokenInfo, err := qtx.TokenByIDAndChainIDAndExternalID(internalCtx, queries.TokenByIDAndChainIDAndExternalIDParams{ ID: token.Address.Bytes(), @@ -367,92 +361,103 @@ func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, if err != nil { return err } - // if the token synced status is not the same that the received one, update - // it in the database - if tokenInfo.Synced != synced { - _, err = qtx.UpdateTokenStatus(internalCtx, queries.UpdateTokenStatusParams{ - ID: token.Address.Bytes(), - ChainID: token.ChainID, - ExternalID: token.ExternalID, - Synced: synced, - }) - if err != nil { - return err - } - if synced { - log.Infow("token synced", - "token", token.Address.Hex(), - "chainID", token.ChainID, - "externalID", token.ExternalID) - } + // update the balance synced status and last block in the database + _, err = qtx.UpdateTokenStatus(internalCtx, queries.UpdateTokenStatusParams{ + ID: token.Address.Bytes(), + ChainID: token.ChainID, + ExternalID: token.ExternalID, + Synced: synced, + LastBlock: int64(lastBlock), + AnalysedTransfers: tokenInfo.AnalysedTransfers + int64(newTransfers), + }) + if err != nil { + return err } + log.Debugw("token status saved", + "synced", synced, + "token", token.Address.Hex(), + "chainID", token.ChainID, + "externalID", token.ExternalID, + "block", lastBlock) + if len(holders) == 0 { + log.Debugw("no holders to save, skipping...", + "token", token.Address.Hex(), + "chainID", token.ChainID, + "externalID", token.ExternalID) + return tx.Commit() + } + // create, update or delete token holders created, updated, deleted := 0, 0, 0 for addr, balance := range holders { - switch balance.Cmp(big.NewInt(0)) { - case -1: - // if the calculated balance is negative,try todelete the token holder - if _, err := qtx.DeleteTokenHolder(ctx, queries.DeleteTokenHolderParams{ + // get the current token holder from the database + currentTokenHolder, err := qtx.TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID(ctx, + queries.TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDParams{ TokenID: token.Address.Bytes(), ChainID: token.ChainID, ExternalID: token.ExternalID, HolderID: addr.Bytes(), - }); err != nil { - return fmt.Errorf("error deleting token holder: %w", err) - } - deleted++ - case 1: - // get the current token holder from the database - currentTokenHolder, err := qtx.TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID(ctx, - queries.TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDParams{ - TokenID: token.Address.Bytes(), - ChainID: token.ChainID, - ExternalID: token.ExternalID, - HolderID: addr.Bytes(), - }) - if err != nil { - if !errors.Is(sql.ErrNoRows, err) { - return err - } - // if the token holder not exists, create it - _, err = qtx.CreateTokenHolder(ctx, queries.CreateTokenHolderParams{ - TokenID: token.Address.Bytes(), - ChainID: token.ChainID, - ExternalID: token.ExternalID, - HolderID: addr.Bytes(), - BlockID: lastBlock, - Balance: balance.String(), - }) - if err != nil { - return err - } - created++ - continue - } - // parse the current token holder balance and compare it with the - // calculated one, if they are the same, continue - currentBalance, ok := new(big.Int).SetString(currentTokenHolder.Balance, 10) - if !ok { - return fmt.Errorf("error parsing current token holder balance") + }) + if err != nil { + if !errors.Is(sql.ErrNoRows, err) { + return err } - if currentBalance.Cmp(balance) == 0 { + // if the holder does not exists in the database and the balance is + // 0 or less, skip it + if balance.Cmp(big.NewInt(0)) != 1 { continue } - // if the calculated balance is not 0 or less and it is different - // from the current one, update it in the database - _, err = qtx.UpdateTokenHolderBalance(ctx, queries.UpdateTokenHolderBalanceParams{ + // if the token holder not exists, create it + _, err = qtx.CreateTokenHolder(ctx, queries.CreateTokenHolderParams{ TokenID: token.Address.Bytes(), ChainID: token.ChainID, ExternalID: token.ExternalID, HolderID: addr.Bytes(), - BlockID: currentTokenHolder.BlockID, - NewBlockID: lastBlock, + BlockID: lastBlock, Balance: balance.String(), }) if err != nil { - return fmt.Errorf("error updating token holder: %w", err) + return err } - updated++ + created++ + continue + } + // if the calculated balance is negative,try todelete the token holder + if balance.Cmp(big.NewInt(0)) != 1 { + if _, err := qtx.DeleteTokenHolder(ctx, queries.DeleteTokenHolderParams{ + TokenID: token.Address.Bytes(), + ChainID: token.ChainID, + ExternalID: token.ExternalID, + HolderID: addr.Bytes(), + }); err != nil { + return fmt.Errorf("error deleting token holder: %w", err) + } + deleted++ + continue + } + // parse the current token holder balance and compare it with the + // calculated one, if they are the same, continue + currentBalance, ok := new(big.Int).SetString(currentTokenHolder.Balance, 10) + if !ok { + return fmt.Errorf("error parsing current token holder balance") + } + if currentBalance.Cmp(balance) == 0 { + continue + } + // if the calculated balance is not 0 or less and it is different + // from the current one, update it in the database + _, err = qtx.UpdateTokenHolderBalance(ctx, queries.UpdateTokenHolderBalanceParams{ + TokenID: token.Address.Bytes(), + ChainID: token.ChainID, + ExternalID: token.ExternalID, + HolderID: addr.Bytes(), + BlockID: currentTokenHolder.BlockID, + NewBlockID: lastBlock, + Balance: balance.String(), + }) + if err != nil { + return fmt.Errorf("error updating token holder: %w", err) } + updated++ } // close the database tx and commit it if err := tx.Commit(); err != nil { From 321e24700d1e9b6cbd6c7bc1cc04a42435b8a065 Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Thu, 25 Jan 2024 17:25:23 +0100 Subject: [PATCH 10/35] almost all differences with holders for ERC20 solved, rest of types remain wrong --- scanner/providers/web3/erc20_provider.go | 53 ++++++------------------ scanner/scanner.go | 37 ++++++----------- 2 files changed, 24 insertions(+), 66 deletions(-) diff --git a/scanner/providers/web3/erc20_provider.go b/scanner/providers/web3/erc20_provider.go index 1f16f4e3..9dfadda5 100644 --- a/scanner/providers/web3/erc20_provider.go +++ b/scanner/providers/web3/erc20_provider.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "math/big" - "sync" "time" "github.com/ethereum/go-ethereum/common" @@ -28,10 +27,6 @@ type ERC20HolderProvider struct { decimals uint64 totalSupply *big.Int creationBlock uint64 - - balances map[common.Address]*big.Int - balancesMtx sync.RWMutex - balancesBlock uint64 } func (p *ERC20HolderProvider) Init(iconf any) error { @@ -41,9 +36,6 @@ func (p *ERC20HolderProvider) Init(iconf any) error { return errors.New("invalid config type, it must be Web3ProviderConfig") } p.endpoints = conf.Endpoints - // reset the internal balances - p.balances = make(map[common.Address]*big.Int) - p.balancesMtx = sync.RWMutex{} // set the reference if the address and chainID are defined in the config if conf.HexAddress != "" && conf.ChainID > 0 { return p.SetRef(Web3ProviderRef{ @@ -85,25 +77,12 @@ func (p *ERC20HolderProvider) SetRef(iref any) error { p.decimals = 0 p.totalSupply = nil p.creationBlock = 0 - // reset balances - p.balancesMtx.Lock() - defer p.balancesMtx.Unlock() - p.balances = make(map[common.Address]*big.Int) - p.balancesBlock = 0 return nil } -func (p *ERC20HolderProvider) SetLastBalances(ctx context.Context, id []byte, - balances map[common.Address]*big.Int, from uint64, +func (p *ERC20HolderProvider) SetLastBalances(_ context.Context, _ []byte, + _ map[common.Address]*big.Int, _ uint64, ) error { - p.balancesMtx.Lock() - defer p.balancesMtx.Unlock() - - if from < p.balancesBlock { - return errors.New("from block is lower than the last block analyzed") - } - p.balancesBlock = from - p.balances = balances return nil } @@ -121,19 +100,16 @@ func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fro "type", providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC20], "from", fromBlock, "to", toBlock) - // some variables to calculate the progress - startTime := time.Now() - p.balancesMtx.RLock() - initialHolders := len(p.balances) - p.balancesMtx.RUnlock() // iterate scanning the logs in the range of blocks until the last block // is reached + startTime := time.Now() logs, lastBlock, synced, err := rangeOfLogs(ctx, p.client, p.address, fromBlock, toBlock, LOG_TOPIC_ERC20_TRANSFER) if err != nil { return nil, 0, fromBlock, false, err } // encode the number of new transfers newTransfers := uint64(len(logs)) + balances := make(map[common.Address]*big.Int) // iterate the logs and update the balances for _, currentLog := range logs { logData, err := p.contract.ERC20ContractFilterer.ParseTransfer(currentLog) @@ -141,29 +117,24 @@ func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fro return nil, newTransfers, lastBlock, false, errors.Join(ErrParsingTokenLogs, fmt.Errorf("[ERC20] %s: %w", p.address, err)) } // update balances - p.balancesMtx.Lock() - if toBalance, ok := p.balances[logData.To]; ok { - p.balances[logData.To] = new(big.Int).Add(toBalance, logData.Value) + if toBalance, ok := balances[logData.To]; ok { + balances[logData.To] = new(big.Int).Add(toBalance, logData.Value) } else { - p.balances[logData.To] = logData.Value + balances[logData.To] = logData.Value } - if fromBalance, ok := p.balances[logData.From]; ok { - p.balances[logData.From] = new(big.Int).Sub(fromBalance, logData.Value) + if fromBalance, ok := balances[logData.From]; ok { + balances[logData.From] = new(big.Int).Sub(fromBalance, logData.Value) } else { - p.balances[logData.From] = new(big.Int).Neg(logData.Value) + balances[logData.From] = new(big.Int).Neg(logData.Value) } - p.balancesMtx.Unlock() } - p.balancesMtx.RLock() - finalHolders := len(p.balances) - p.balancesMtx.RUnlock() log.Infow("saving blocks", - "count", finalHolders-initialHolders, + "count", len(balances), "logs", len(logs), "blocks/s", 1000*float32(lastBlock-fromBlock)/float32(time.Since(startTime).Milliseconds()), "took", time.Since(startTime).Seconds(), "progress", fmt.Sprintf("%d%%", (fromBlock*100)/toBlock)) - return p.balances, newTransfers, lastBlock, synced, nil + return balances, newTransfers, lastBlock, synced, nil } func (p *ERC20HolderProvider) Close() error { diff --git a/scanner/scanner.go b/scanner/scanner.go index 8b73c830..7f1e69c1 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -318,6 +318,15 @@ func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) ( // synced status if it is different from the received one. Then, it creates, // updates or deletes the token holders in the database depending on the // calculated balance. +// WARNING: the following code could produce holders with negative balances +// in the database. This is because the scanner does not know if the token +// holder is a contract or not, so it does not know if the balance is +// correct or not. The scanner assumes that the balance is correct and +// updates it in the database: +// 1. To get the correct holders from the database you must filter the +// holders with negative balances. +// 2. To get the correct balances you must use the contract methods to get +// the balances of the holders. func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, holders map[common.Address]*big.Int, newTransfers, lastBlock uint64, synced bool, @@ -328,7 +337,6 @@ func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, "externalID", token.ExternalID, "block", lastBlock, "holders", len(holders)) - s.tokensMtx.Lock() for i, t := range s.tokens { if t.Address == token.Address && t.ChainID == token.ChainID && t.ExternalID == token.ExternalID { @@ -401,11 +409,6 @@ func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, if !errors.Is(sql.ErrNoRows, err) { return err } - // if the holder does not exists in the database and the balance is - // 0 or less, skip it - if balance.Cmp(big.NewInt(0)) != 1 { - continue - } // if the token holder not exists, create it _, err = qtx.CreateTokenHolder(ctx, queries.CreateTokenHolderParams{ TokenID: token.Address.Bytes(), @@ -421,28 +424,12 @@ func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, created++ continue } - // if the calculated balance is negative,try todelete the token holder - if balance.Cmp(big.NewInt(0)) != 1 { - if _, err := qtx.DeleteTokenHolder(ctx, queries.DeleteTokenHolderParams{ - TokenID: token.Address.Bytes(), - ChainID: token.ChainID, - ExternalID: token.ExternalID, - HolderID: addr.Bytes(), - }); err != nil { - return fmt.Errorf("error deleting token holder: %w", err) - } - deleted++ - continue - } - // parse the current token holder balance and compare it with the - // calculated one, if they are the same, continue + // compute the new balance of the holder currentBalance, ok := new(big.Int).SetString(currentTokenHolder.Balance, 10) if !ok { return fmt.Errorf("error parsing current token holder balance") } - if currentBalance.Cmp(balance) == 0 { - continue - } + newBalance := new(big.Int).Add(currentBalance, balance) // if the calculated balance is not 0 or less and it is different // from the current one, update it in the database _, err = qtx.UpdateTokenHolderBalance(ctx, queries.UpdateTokenHolderBalanceParams{ @@ -452,7 +439,7 @@ func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, HolderID: addr.Bytes(), BlockID: currentTokenHolder.BlockID, NewBlockID: lastBlock, - Balance: balance.String(), + Balance: newBalance.String(), }) if err != nil { return fmt.Errorf("error updating token holder: %w", err) From 59b508661c59f784778b4077a9dc9618b49df71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Fri, 26 Jan 2024 12:09:01 +0100 Subject: [PATCH 11/35] fixed issues with balances for every provider type, tests fixed --- scanner/providers/gitcoin/gitcoin.go | 83 +++++++------------- scanner/providers/gitcoin/gitcoin_test.go | 16 ++-- scanner/providers/helpers.go | 47 +++++++++++ scanner/providers/poap/poap_provider.go | 65 +++------------ scanner/providers/poap/poap_provider_test.go | 57 -------------- scanner/providers/types.go | 2 +- scanner/providers/web3/erc20_provider.go | 9 +++ scanner/providers/web3/erc721_provider.go | 62 +++++---------- scanner/providers/web3/erc777_provider.go | 61 +++++--------- 9 files changed, 150 insertions(+), 252 deletions(-) create mode 100644 scanner/providers/helpers.go diff --git a/scanner/providers/gitcoin/gitcoin.go b/scanner/providers/gitcoin/gitcoin.go index 3d09b522..4ab60a11 100644 --- a/scanner/providers/gitcoin/gitcoin.go +++ b/scanner/providers/gitcoin/gitcoin.go @@ -21,6 +21,7 @@ import ( const ( dateLayout = "2006-01-02T15:04:05.999Z" + hexAddress = "0x000000000000000000000000000000000000006C" ) type gitcoinScoreResult struct { @@ -35,6 +36,7 @@ type gitcoinScoreResult struct { type GitcoinPassport struct { // public endpoint to download the json apiEndpoint string + cooldown time.Duration // internal vars to manage the download ctx context.Context cancel context.CancelFunc @@ -45,12 +47,12 @@ type GitcoinPassport struct { newBalancesMtx sync.RWMutex currentBalances map[common.Address]*big.Int currentBalancesMtx sync.RWMutex - lastUpdate time.Time + lastUpdate atomic.Value } type GitcoinPassportConf struct { APIEndpoint string - Cooldown time.Duration + Cooldown time.Duration } func (g *GitcoinPassport) Init(iconf any) error { @@ -59,6 +61,7 @@ func (g *GitcoinPassport) Init(iconf any) error { return fmt.Errorf("invalid config type") } g.apiEndpoint = conf.APIEndpoint + g.cooldown = conf.Cooldown // init download variables g.ctx, g.cancel = context.WithCancel(context.Background()) g.downloading = new(atomic.Bool) @@ -70,7 +73,7 @@ func (g *GitcoinPassport) Init(iconf any) error { g.currentBalancesMtx = sync.RWMutex{} g.newBalances = make(map[common.Address]*big.Int) g.newBalancesMtx = sync.RWMutex{} - g.lastUpdate = time.Time{} + g.lastUpdate.Store(time.Time{}) return nil } @@ -88,13 +91,12 @@ func (g *GitcoinPassport) SetLastBalances(_ context.Context, _ []byte, balances return nil } -<<<<<<< HEAD:scanner/providers/gitcoin/gitcoin.go func (g *GitcoinPassport) HoldersBalances(_ context.Context, _ []byte, _ uint64) (map[common.Address]*big.Int, uint64, uint64, bool, error) { - if time.Since(g.lastUpdate) > 12*time.Hour && !g.downloading.Load() { -======= -func (g *GitcoinPassport) HoldersBalances(_ context.Context, _ []byte, _ uint64) (map[common.Address]*big.Int, error) { - if time.Since(g.lastUpdate) > g.Cooldown && !g.downloading.Load() { ->>>>>>> main:service/gitcoin/gitcoin.go + lastUpdate, ok := g.lastUpdate.Load().(time.Time) + if !ok { + return nil, 1, 0, false, fmt.Errorf("error getting last update") + } + if time.Since(lastUpdate) > g.cooldown && !g.downloading.Load() { log.Info("downloading Gitcoin Passport balances") go func() { g.downloading.Store(true) @@ -107,19 +109,19 @@ func (g *GitcoinPassport) HoldersBalances(_ context.Context, _ []byte, _ uint64) } }() } - lastUpdate := uint64(g.lastUpdate.Unix()) + lastUpdateID := uint64(lastUpdate.Unix()) if g.updated.Load() { log.Info("retrieving last Gitcoin Passport balances") g.updated.Store(false) - return g.calcPartials(), 1, lastUpdate, true, nil + + g.currentBalancesMtx.RLock() + g.newBalancesMtx.RLock() + defer g.currentBalancesMtx.RUnlock() + defer g.newBalancesMtx.RUnlock() + return providers.CalcPartialHolders(g.currentBalances, g.newBalances), 1, lastUpdateID, true, nil } -<<<<<<< HEAD:scanner/providers/gitcoin/gitcoin.go - log.Info("no changes in Gitcoin Passport balances from last 12 hours") - return nil, 1, lastUpdate, true, nil -======= - log.Infof("no changes in Gitcoin Passport balances from last %s", g.Cooldown) - return nil, nil ->>>>>>> main:service/gitcoin/gitcoin.go + log.Infof("no changes in Gitcoin Passport balances from last %s", g.cooldown) + return nil, 1, lastUpdateID, true, nil } func (g *GitcoinPassport) updateBalances() error { @@ -192,60 +194,31 @@ func (g *GitcoinPassport) updateBalances() error { g.newBalancesMtx.Lock() defer g.newBalancesMtx.Unlock() g.newBalances = balances - g.lastUpdate = time.Now() + g.lastUpdate.Store(time.Now()) return nil } -func (g *GitcoinPassport) calcPartials() map[common.Address]*big.Int { - g.currentBalancesMtx.Lock() - g.newBalancesMtx.Lock() - defer g.currentBalancesMtx.Unlock() - defer g.newBalancesMtx.Unlock() - - partialBalances := make(map[common.Address]*big.Int) - for addr, newBalance := range g.newBalances { - currentBalance, alreadyExists := g.currentBalances[addr] - if !alreadyExists { - partialBalances[addr] = newBalance - continue - } - partialBalances[addr] = new(big.Int).Sub(newBalance, currentBalance) - } - - for addr, currentBalance := range g.currentBalances { - if _, exists := g.newBalances[addr]; !exists { - partialBalances[addr] = new(big.Int).Neg(currentBalance) - } - } - return partialBalances -} - func (g *GitcoinPassport) Close() error { g.cancel() return nil } -<<<<<<< HEAD:scanner/providers/gitcoin/gitcoin.go func (g *GitcoinPassport) IsExternal() bool { return true -======= +} + func (g *GitcoinPassport) IsSynced(_ []byte) bool { g.currentBalancesMtx.RLock() defer g.currentBalancesMtx.RUnlock() return len(g.currentBalances) > 0 } -func (g *GitcoinPassport) Address(_ context.Context, _ []byte) (common.Address, error) { - return common.HexToAddress("0x000000000000000000000000000000000000006C"), nil ->>>>>>> main:service/gitcoin/gitcoin.go -} - func (g *GitcoinPassport) Address() common.Address { - return common.HexToAddress("0x000000000000000000000000000000000000006C") + return common.HexToAddress(hexAddress) } func (g *GitcoinPassport) Type() uint64 { - return providers.CONTRACT_TYPE_POAP + return providers.CONTRACT_TYPE_GITCOIN } func (g *GitcoinPassport) ChainID() uint64 { @@ -281,7 +254,11 @@ func (g *GitcoinPassport) BlockTimestamp(_ context.Context, _ uint64) (string, e } func (g *GitcoinPassport) BlockRootHash(_ context.Context, _ uint64) ([]byte, error) { - timeHash := md5.Sum([]byte(g.lastUpdate.Format(time.RFC3339))) + lastUpdate, ok := g.lastUpdate.Load().(time.Time) + if !ok { + return nil, fmt.Errorf("error getting last update") + } + timeHash := md5.Sum([]byte(lastUpdate.Format(time.RFC3339))) return timeHash[:], nil } diff --git a/scanner/providers/gitcoin/gitcoin_test.go b/scanner/providers/gitcoin/gitcoin_test.go index 6115c926..6a7459e5 100644 --- a/scanner/providers/gitcoin/gitcoin_test.go +++ b/scanner/providers/gitcoin/gitcoin_test.go @@ -3,11 +3,13 @@ package gitcoin import ( "context" "fmt" + "math/big" "net/http" "strings" "testing" "time" + "github.com/ethereum/go-ethereum/common" qt "github.com/frankban/quicktest" ) @@ -19,10 +21,7 @@ var ( "0x2b1a6dd2a80f7e9a2305205572df0f4b38b205a1": "0", } expectedUpdatedHolders = map[string]string{ - "0x85ff01cff157199527528788ec4ea6336615c989": "10", - "0x7587cfbd20e5a970209526b4d1f69dbaae8bed37": "9", - "0x7bec70fa7ef926878858333b0fa581418e2ef0b5": "1", - "0x2b1a6dd2a80f7e9a2305205572df0f4b38b205a1": "0", + "0x85ff01cff157199527528788ec4ea6336615c989": "-2", } ) @@ -47,7 +46,7 @@ func TestGitcoinPassport(t *testing.T) { originalEndpoint, updatedEndpoint := serveStaticFile("./mocked_data.jsonl", "./mocked_data_updated.jsonl") // create the provider provider := new(GitcoinPassport) - c.Assert(provider.Init(GitcoinPassportConf{originalEndpoint}), qt.IsNil) + c.Assert(provider.Init(GitcoinPassportConf{originalEndpoint, time.Second * 2}), qt.IsNil) // start the first download emptyBalances, _, _, _, err := provider.HoldersBalances(context.TODO(), nil, 0) c.Assert(err, qt.IsNil) @@ -71,13 +70,18 @@ func TestGitcoinPassport(t *testing.T) { c.Assert(len(sameBalances), qt.Equals, 0) provider.apiEndpoint = updatedEndpoint - provider.lastUpdate = time.Time{} + provider.lastUpdate.Store(time.Time{}) emptyBalances, _, _, _, err = provider.HoldersBalances(context.TODO(), nil, 0) c.Assert(err, qt.IsNil) c.Assert(len(emptyBalances), qt.Equals, 0) time.Sleep(2 * time.Second) // check the balances + currentHolders := make(map[common.Address]*big.Int) + for addr, balance := range expectedOriginalHolders { + currentHolders[common.HexToAddress(addr)], _ = new(big.Int).SetString(balance, 10) + } + provider.SetLastBalances(context.TODO(), nil, currentHolders, 0) holders, _, _, _, err = provider.HoldersBalances(context.TODO(), nil, 0) c.Assert(err, qt.IsNil) c.Assert(len(holders), qt.Equals, len(expectedUpdatedHolders)) diff --git a/scanner/providers/helpers.go b/scanner/providers/helpers.go new file mode 100644 index 00000000..addf8e4a --- /dev/null +++ b/scanner/providers/helpers.go @@ -0,0 +1,47 @@ +package providers + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" +) + +// CalcPartialHolders calculates the partial holders from the current and new holders +// maps. It returns a map with the partial holders and their balances. The final +// holders are calculated as: +// 1. Holders that are in the new holders map but not in the current holders +// map. They are created with the balance of the new holders. +// 2. Holders that are in the new and the current holders maps and have a +// different balance. They are updated with difference between the new +// and the current balances. +// 3. Holders that are in the current holders map but not in the new holders +// map. They are updated with the balance of the current holders negated. +func CalcPartialHolders(currentHolders, newHolders map[common.Address]*big.Int) map[common.Address]*big.Int { + partialHolders := make(map[common.Address]*big.Int) + // calculate holders of type 1 and 2 + for addr, newBalance := range newHolders { + // if the address is not in the current holders, it is a holder of type 1 + // so we add it to the partial holders with the new balance + currentBalance, alreadyExists := currentHolders[addr] + if !alreadyExists { + partialHolders[addr] = newBalance + continue + } + // if the address is in the current holders, it is a holder of type 2 + // so we add it to the partial holders with the difference between the + // new and the current balances, if the difference is not zero (if it + // is zero, it has not changed it balance) + if diff := new(big.Int).Sub(newBalance, currentBalance); diff.Cmp(big.NewInt(0)) != 0 { + partialHolders[addr] = diff + } + } + // calculate holders of type 3 + for addr, currentBalance := range currentHolders { + // if the address is not in the new holders, it is a holder of type 3 + // so we add it to the partial holders with the current balance negated + if _, exists := newHolders[addr]; !exists { + partialHolders[addr] = new(big.Int).Neg(currentBalance) + } + } + return partialHolders +} diff --git a/scanner/providers/poap/poap_provider.go b/scanner/providers/poap/poap_provider.go index 22838539..fb1008b5 100644 --- a/scanner/providers/poap/poap_provider.go +++ b/scanner/providers/poap/poap_provider.go @@ -131,22 +131,23 @@ func (p *POAPHolderProvider) HoldersBalances(_ context.Context, id []byte, delta if err != nil { return nil, 0, 0, false, err } - // calculate snapshot from + p.snapshotsMtx.RLock() + defer p.snapshotsMtx.RUnlock() + // if there is no snapshot, the final snapshot is the new snapshot, otherwise + // calculate the partials balances from the last snapshot from := delta - if snapshot, exist := p.snapshots[string(id)]; exist { - from += snapshot.from + finalSnapshot := newSnapshot + if currentSnapshot, exist := p.snapshots[eventID]; exist { + finalSnapshot = providers.CalcPartialHolders(currentSnapshot.snapshot, newSnapshot) + from += currentSnapshot.from } - // calculate partials balances - partialBalances := p.calcPartials(eventID, newSnapshot) - // save snapshot - p.snapshotsMtx.Lock() - defer p.snapshotsMtx.Unlock() + // store the new snapshot p.snapshots[string(id)] = &POAPSnapshot{ from: from, snapshot: newSnapshot, } - // return partials from last snapshot - return partialBalances, 1, from, true, nil + // return the final snapshot + return finalSnapshot, uint64(len(finalSnapshot)), from, true, nil } // Close method is not implemented in the POAP external provider. By default it @@ -372,46 +373,4 @@ func (p *POAPHolderProvider) getEventInfo(eventID string) (*EventAPIResponse, er return nil, err } return &eventRes, nil -} - -// calcPartials calculates the partials balances of the token holders for the -// given eventID and new snapshot. It returns a map with the address of the -// holder as key and the balance of the token holder as value. The partials -// balances will include: -// - holders from the new snapshot that are not in the current snapshot with -// the balance of the new snapshot -// - holders from the current snapshot that are not in the new snapshot but -// with zero balance -// - holders from the current snapshot that are in the new snapshot with the -// balance of the new snapshot if the balance has changed -func (p *POAPHolderProvider) calcPartials(eventID string, newSnapshot map[common.Address]*big.Int) map[common.Address]*big.Int { - // get current snapshot if exists - p.snapshotsMtx.RLock() - defer p.snapshotsMtx.RUnlock() - current, exist := p.snapshots[eventID] - if !exist { - return newSnapshot - } - // calculate partials balances, if the address is not in the current - // snapshot, the partial balance will be the balance of the new snapshot - // if the address is in the current snapshot, the partial balance will be - // the difference between the balance of the new snapshot and the balance - // of the current snapshot - partialBalances := map[common.Address]*big.Int{} - for addr, newBalance := range newSnapshot { - currentBalance, alreadyExists := current.snapshot[addr] - if !alreadyExists { - partialBalances[addr] = newBalance - continue - } - partialBalances[addr] = new(big.Int).Sub(newBalance, currentBalance) - } - // add the addresses from the current snapshot that are not in the new - // snapshot with negative balance - for addr, currentBalance := range current.snapshot { - if _, exists := newSnapshot[addr]; !exists { - partialBalances[addr] = new(big.Int).Neg(currentBalance) - } - } - return partialBalances -} +} \ No newline at end of file diff --git a/scanner/providers/poap/poap_provider_test.go b/scanner/providers/poap/poap_provider_test.go index fa599ad3..c420335c 100644 --- a/scanner/providers/poap/poap_provider_test.go +++ b/scanner/providers/poap/poap_provider_test.go @@ -1,58 +1 @@ package poap - -import ( - "context" - "math/big" - "sync" - "testing" - - "github.com/ethereum/go-ethereum/common" - qt "github.com/frankban/quicktest" -) - -func TestPOAPHolderProvider_calcPartials(t *testing.T) { - c := qt.New(t) - // create a new POAPHolderProvider - p := &POAPHolderProvider{ - snapshots: make(map[string]*POAPSnapshot), - snapshotsMtx: &sync.RWMutex{}, - } - p.snapshots = make(map[string]*POAPSnapshot) - // calculate the partial balances with the mocked current and new snapshots - eventID := "1234" - currentSnapshot := map[common.Address]*big.Int{ - common.HexToAddress("0x1"): big.NewInt(1), - common.HexToAddress("0x2"): big.NewInt(2), - common.HexToAddress("0x3"): big.NewInt(3), - } - initialSnapshot := p.calcPartials(eventID, currentSnapshot) - c.Assert(len(initialSnapshot), qt.Equals, len(currentSnapshot)) - for addr, balance := range currentSnapshot { - resultingBalance, exist := initialSnapshot[addr] - c.Assert(exist, qt.Equals, true) - c.Assert(resultingBalance.Cmp(balance), qt.Equals, 0, qt.Commentf("address %s", addr.Hex())) - } - // create a new snapshot with the mocked changes and set the current - // snapshot as last balances of the event - newSnapshot := map[common.Address]*big.Int{ - common.HexToAddress("0x1"): big.NewInt(1), // keep 0x1 unchanged - // delete 0x2 - common.HexToAddress("0x3"): big.NewInt(2), // update 0x3 - common.HexToAddress("0x4"): big.NewInt(1), // add 0x4 - } - expected := map[common.Address]*big.Int{ - common.HexToAddress("0x1"): big.NewInt(0), - common.HexToAddress("0x2"): big.NewInt(-2), - common.HexToAddress("0x3"): big.NewInt(-1), - common.HexToAddress("0x4"): big.NewInt(1), - } - // check that the calcPartials method returns the expected results - c.Assert(p.SetLastBalances(context.TODO(), []byte(eventID), currentSnapshot, 0), qt.IsNil) - partialBalances := p.calcPartials(eventID, newSnapshot) - c.Assert(len(partialBalances), qt.Equals, len(expected)) - for addr, balance := range expected { - resultingBalance, exist := partialBalances[addr] - c.Assert(exist, qt.Equals, true) - c.Assert(resultingBalance.Cmp(balance), qt.Equals, 0, qt.Commentf("address %s", addr.Hex())) - } -} diff --git a/scanner/providers/types.go b/scanner/providers/types.go index 0f805df6..2d16689d 100644 --- a/scanner/providers/types.go +++ b/scanner/providers/types.go @@ -14,7 +14,7 @@ const ( CONTRACT_NAME_ERC721 = "erc721" CONTRACT_NAME_ERC777 = "erc777" CONTRACT_NAME_POAP = "poap" - CONTRACT_NAME_GITCOIN = "GITCOIN" + CONTRACT_NAME_GITCOIN = "gitcoinpassport" ) var TokenTypeStringMap = map[uint64]string{ diff --git a/scanner/providers/web3/erc20_provider.go b/scanner/providers/web3/erc20_provider.go index 9dfadda5..c6a98e2a 100644 --- a/scanner/providers/web3/erc20_provider.go +++ b/scanner/providers/web3/erc20_provider.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math/big" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -27,6 +28,7 @@ type ERC20HolderProvider struct { decimals uint64 totalSupply *big.Int creationBlock uint64 + synced atomic.Bool } func (p *ERC20HolderProvider) Init(iconf any) error { @@ -36,6 +38,7 @@ func (p *ERC20HolderProvider) Init(iconf any) error { return errors.New("invalid config type, it must be Web3ProviderConfig") } p.endpoints = conf.Endpoints + p.synced.Store(false) // set the reference if the address and chainID are defined in the config if conf.HexAddress != "" && conf.ChainID > 0 { return p.SetRef(Web3ProviderRef{ @@ -77,6 +80,7 @@ func (p *ERC20HolderProvider) SetRef(iref any) error { p.decimals = 0 p.totalSupply = nil p.creationBlock = 0 + p.synced.Store(false) return nil } @@ -134,6 +138,7 @@ func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fro "blocks/s", 1000*float32(lastBlock-fromBlock)/float32(time.Since(startTime).Milliseconds()), "took", time.Since(startTime).Seconds(), "progress", fmt.Sprintf("%d%%", (fromBlock*100)/toBlock)) + p.synced.Store(synced) return balances, newTransfers, lastBlock, synced, nil } @@ -145,6 +150,10 @@ func (p *ERC20HolderProvider) IsExternal() bool { return false } +func (p *ERC20HolderProvider) IsSynced(_ []byte) bool { + return p.synced.Load() +} + func (p *ERC20HolderProvider) Address() common.Address { return p.address } diff --git a/scanner/providers/web3/erc721_provider.go b/scanner/providers/web3/erc721_provider.go index eead600a..204fe313 100644 --- a/scanner/providers/web3/erc721_provider.go +++ b/scanner/providers/web3/erc721_provider.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" "math/big" - "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -28,10 +28,7 @@ type ERC721HolderProvider struct { decimals uint64 totalSupply *big.Int creationBlock uint64 - - balances map[common.Address]*big.Int - balancesMtx sync.RWMutex - balancesBlock uint64 + synced atomic.Bool } func (p *ERC721HolderProvider) Init(iconf any) error { @@ -41,9 +38,7 @@ func (p *ERC721HolderProvider) Init(iconf any) error { return errors.New("invalid config type, it must be Web3ProviderConfig") } p.endpoints = conf.Endpoints - // reset the internal balances - p.balances = make(map[common.Address]*big.Int) - p.balancesMtx = sync.RWMutex{} + p.synced.Store(false) // set the reference if the address and chainID are defined in the config if conf.HexAddress != "" && conf.ChainID > 0 { return p.SetRef(Web3ProviderRef{ @@ -85,25 +80,13 @@ func (p *ERC721HolderProvider) SetRef(iref any) error { p.decimals = 0 p.totalSupply = nil p.creationBlock = 0 - // reset balances - p.balancesMtx.Lock() - defer p.balancesMtx.Unlock() - p.balances = make(map[common.Address]*big.Int) - p.balancesBlock = 0 + p.synced.Store(false) return nil } -func (p *ERC721HolderProvider) SetLastBalances(ctx context.Context, id []byte, - balances map[common.Address]*big.Int, from uint64, +func (p *ERC721HolderProvider) SetLastBalances(_ context.Context, _ []byte, + _ map[common.Address]*big.Int, _ uint64, ) error { - p.balancesMtx.Lock() - defer p.balancesMtx.Unlock() - - if from < p.balancesBlock { - return errors.New("from block is lower than the last block analyzed") - } - p.balancesBlock = from - p.balances = balances return nil } @@ -121,19 +104,16 @@ func (p *ERC721HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fr "type", providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC721], "from", fromBlock, "to", toBlock) - // some variables to calculate the progress - startTime := time.Now() - p.balancesMtx.RLock() - initialHolders := len(p.balances) - p.balancesMtx.RUnlock() // iterate scanning the logs in the range of blocks until the last block // is reached + startTime := time.Now() logs, lastBlock, synced, err := rangeOfLogs(ctx, p.client, p.address, fromBlock, toBlock, LOG_TOPIC_ERC20_TRANSFER) if err != nil { return nil, 0, fromBlock, false, err } // encode the number of new transfers newTransfers := uint64(len(logs)) + balances := make(map[common.Address]*big.Int) // iterate the logs and update the balances for _, currentLog := range logs { logData, err := p.contract.ERC721ContractFilterer.ParseTransfer(currentLog) @@ -141,29 +121,25 @@ func (p *ERC721HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fr return nil, newTransfers, lastBlock, false, fmt.Errorf("[ERC721] %w: %s: %w", ErrParsingTokenLogs, p.address.Hex(), err) } // update balances - p.balancesMtx.Lock() - if toBalance, ok := p.balances[logData.To]; ok { - p.balances[logData.To] = new(big.Int).Add(toBalance, big.NewInt(1)) + if toBalance, ok := balances[logData.To]; ok { + balances[logData.To] = new(big.Int).Add(toBalance, big.NewInt(1)) } else { - p.balances[logData.To] = big.NewInt(1) + balances[logData.To] = big.NewInt(1) } - if fromBalance, ok := p.balances[logData.From]; ok { - p.balances[logData.From] = new(big.Int).Sub(fromBalance, big.NewInt(1)) + if fromBalance, ok := balances[logData.From]; ok { + balances[logData.From] = new(big.Int).Sub(fromBalance, big.NewInt(1)) } else { - p.balances[logData.From] = big.NewInt(-1) + balances[logData.From] = big.NewInt(-1) } - p.balancesMtx.Unlock() } - p.balancesMtx.RLock() - finalHolders := len(p.balances) - p.balancesMtx.RUnlock() log.Infow("saving blocks", - "count", finalHolders-initialHolders, + "count", len(balances), "logs", len(logs), "blocks/s", 1000*float32(lastBlock-fromBlock)/float32(time.Since(startTime).Milliseconds()), "took", time.Since(startTime).Seconds(), "progress", fmt.Sprintf("%d%%", (fromBlock*100)/toBlock)) - return p.balances, newTransfers, lastBlock, synced, nil + p.synced.Store(synced) + return balances, newTransfers, lastBlock, synced, nil } func (p *ERC721HolderProvider) Close() error { @@ -174,6 +150,10 @@ func (p *ERC721HolderProvider) IsExternal() bool { return false } +func (p *ERC721HolderProvider) IsSynced(_ []byte) bool { + return p.synced.Load() +} + func (p *ERC721HolderProvider) Address() common.Address { return p.address } diff --git a/scanner/providers/web3/erc777_provider.go b/scanner/providers/web3/erc777_provider.go index 5c84c8c3..a066e1e1 100644 --- a/scanner/providers/web3/erc777_provider.go +++ b/scanner/providers/web3/erc777_provider.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" "math/big" - "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -28,10 +28,7 @@ type ERC777HolderProvider struct { decimals uint64 totalSupply *big.Int creationBlock uint64 - - balances map[common.Address]*big.Int - balancesMtx sync.RWMutex - balancesBlock uint64 + synced atomic.Bool } func (p *ERC777HolderProvider) Init(iconf any) error { @@ -41,9 +38,7 @@ func (p *ERC777HolderProvider) Init(iconf any) error { return errors.New("invalid config type, it must be Web3ProviderConfig") } p.endpoints = conf.Endpoints - // reset the internal balances - p.balances = make(map[common.Address]*big.Int) - p.balancesMtx = sync.RWMutex{} + p.synced.Store(false) // set the reference if the address and chainID are defined in the config if conf.HexAddress != "" && conf.ChainID > 0 { return p.SetRef(Web3ProviderRef{ @@ -85,25 +80,13 @@ func (p *ERC777HolderProvider) SetRef(iref any) error { p.decimals = 0 p.totalSupply = nil p.creationBlock = 0 - // reset balances - p.balancesMtx.Lock() - defer p.balancesMtx.Unlock() - p.balances = make(map[common.Address]*big.Int) - p.balancesBlock = 0 + p.synced.Store(false) return nil } -func (p *ERC777HolderProvider) SetLastBalances(ctx context.Context, id []byte, - balances map[common.Address]*big.Int, from uint64, +func (p *ERC777HolderProvider) SetLastBalances(_ context.Context, _ []byte, + _ map[common.Address]*big.Int, _ uint64, ) error { - p.balancesMtx.Lock() - defer p.balancesMtx.Unlock() - - if from < p.balancesBlock { - return errors.New("from block is lower than the last block analyzed") - } - p.balancesBlock = from - p.balances = balances return nil } @@ -121,19 +104,16 @@ func (p *ERC777HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fr "type", providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC777], "from", fromBlock, "to", toBlock) - // some variables to calculate the progress - startTime := time.Now() - p.balancesMtx.RLock() - initialHolders := len(p.balances) - p.balancesMtx.RUnlock() // iterate scanning the logs in the range of blocks until the last block // is reached + startTime := time.Now() logs, lastBlock, synced, err := rangeOfLogs(ctx, p.client, p.address, fromBlock, toBlock, LOG_TOPIC_ERC20_TRANSFER) if err != nil { return nil, 0, fromBlock, false, err } // encode the number of new transfers newTransfers := uint64(len(logs)) + balances := make(map[common.Address]*big.Int) // iterate the logs and update the balances for _, currentLog := range logs { logData, err := p.contract.ERC777ContractFilterer.ParseTransfer(currentLog) @@ -141,29 +121,24 @@ func (p *ERC777HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fr return nil, newTransfers, lastBlock, false, errors.Join(ErrParsingTokenLogs, fmt.Errorf("[ERC777] %s: %w", p.address, err)) } // update balances - p.balancesMtx.Lock() - if toBalance, ok := p.balances[logData.To]; ok { - p.balances[logData.To] = new(big.Int).Add(toBalance, big.NewInt(1)) + if toBalance, ok := balances[logData.To]; ok { + balances[logData.To] = new(big.Int).Add(toBalance, big.NewInt(1)) } else { - p.balances[logData.To] = big.NewInt(1) + balances[logData.To] = big.NewInt(1) } - if fromBalance, ok := p.balances[logData.From]; ok { - p.balances[logData.From] = new(big.Int).Sub(fromBalance, big.NewInt(1)) + if fromBalance, ok := balances[logData.From]; ok { + balances[logData.From] = new(big.Int).Sub(fromBalance, big.NewInt(1)) } else { - p.balances[logData.From] = big.NewInt(-1) + balances[logData.From] = big.NewInt(-1) } - p.balancesMtx.Unlock() } - p.balancesMtx.RLock() - finalHolders := len(p.balances) - p.balancesMtx.RUnlock() log.Infow("saving blocks", - "count", finalHolders-initialHolders, + "count", len(balances), "logs", len(logs), "blocks/s", 1000*float32(lastBlock-fromBlock)/float32(time.Since(startTime).Milliseconds()), "took", time.Since(startTime).Seconds(), "progress", fmt.Sprintf("%d%%", (fromBlock*100)/toBlock)) - return p.balances, newTransfers, lastBlock, synced, nil + return balances, newTransfers, lastBlock, synced, nil } func (p *ERC777HolderProvider) Close() error { @@ -174,6 +149,10 @@ func (p *ERC777HolderProvider) IsExternal() bool { return false } +func (p *ERC777HolderProvider) IsSynced(_ []byte) bool { + return p.synced.Load() +} + func (p *ERC777HolderProvider) Address() common.Address { return p.address } From 84e693c990768ca6f726409043f971c5941bc8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Fri, 26 Jan 2024 12:14:44 +0100 Subject: [PATCH 12/35] fix linter suggestions --- scanner/providers/gitcoin/gitcoin.go | 11 ++++++++--- scanner/providers/gitcoin/gitcoin_test.go | 2 +- scanner/providers/poap/poap_provider.go | 4 ++-- scanner/scanner.go | 4 +++- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/scanner/providers/gitcoin/gitcoin.go b/scanner/providers/gitcoin/gitcoin.go index 4ab60a11..c86d554c 100644 --- a/scanner/providers/gitcoin/gitcoin.go +++ b/scanner/providers/gitcoin/gitcoin.go @@ -81,7 +81,9 @@ func (g *GitcoinPassport) SetRef(_ any) error { return nil } -func (g *GitcoinPassport) SetLastBalances(_ context.Context, _ []byte, balances map[common.Address]*big.Int, _ uint64) error { +func (g *GitcoinPassport) SetLastBalances(_ context.Context, _ []byte, + balances map[common.Address]*big.Int, _ uint64, +) error { log.Infof("setting last balances for %d addresses", len(balances)) g.currentBalancesMtx.Lock() defer g.currentBalancesMtx.Unlock() @@ -91,7 +93,9 @@ func (g *GitcoinPassport) SetLastBalances(_ context.Context, _ []byte, balances return nil } -func (g *GitcoinPassport) HoldersBalances(_ context.Context, _ []byte, _ uint64) (map[common.Address]*big.Int, uint64, uint64, bool, error) { +func (g *GitcoinPassport) HoldersBalances(_ context.Context, _ []byte, _ uint64) ( + map[common.Address]*big.Int, uint64, uint64, bool, error, +) { lastUpdate, ok := g.lastUpdate.Load().(time.Time) if !ok { return nil, 1, 0, false, fmt.Errorf("error getting last update") @@ -118,7 +122,8 @@ func (g *GitcoinPassport) HoldersBalances(_ context.Context, _ []byte, _ uint64) g.newBalancesMtx.RLock() defer g.currentBalancesMtx.RUnlock() defer g.newBalancesMtx.RUnlock() - return providers.CalcPartialHolders(g.currentBalances, g.newBalances), 1, lastUpdateID, true, nil + return providers.CalcPartialHolders(g.currentBalances, g.newBalances), + 1, lastUpdateID, true, nil } log.Infof("no changes in Gitcoin Passport balances from last %s", g.cooldown) return nil, 1, lastUpdateID, true, nil diff --git a/scanner/providers/gitcoin/gitcoin_test.go b/scanner/providers/gitcoin/gitcoin_test.go index 6a7459e5..cd3cd51f 100644 --- a/scanner/providers/gitcoin/gitcoin_test.go +++ b/scanner/providers/gitcoin/gitcoin_test.go @@ -81,7 +81,7 @@ func TestGitcoinPassport(t *testing.T) { for addr, balance := range expectedOriginalHolders { currentHolders[common.HexToAddress(addr)], _ = new(big.Int).SetString(balance, 10) } - provider.SetLastBalances(context.TODO(), nil, currentHolders, 0) + c.Assert(provider.SetLastBalances(context.TODO(), nil, currentHolders, 0), qt.IsNil) holders, _, _, _, err = provider.HoldersBalances(context.TODO(), nil, 0) c.Assert(err, qt.IsNil) c.Assert(len(holders), qt.Equals, len(expectedUpdatedHolders)) diff --git a/scanner/providers/poap/poap_provider.go b/scanner/providers/poap/poap_provider.go index fb1008b5..4d97d033 100644 --- a/scanner/providers/poap/poap_provider.go +++ b/scanner/providers/poap/poap_provider.go @@ -146,7 +146,7 @@ func (p *POAPHolderProvider) HoldersBalances(_ context.Context, id []byte, delta from: from, snapshot: newSnapshot, } - // return the final snapshot + // return the final snapshot return finalSnapshot, uint64(len(finalSnapshot)), from, true, nil } @@ -373,4 +373,4 @@ func (p *POAPHolderProvider) getEventInfo(eventID string) (*EventAPIResponse, er return nil, err } return &eventRes, nil -} \ No newline at end of file +} diff --git a/scanner/scanner.go b/scanner/scanner.go index 7f1e69c1..1c4bb229 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -308,7 +308,9 @@ func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) ( return nil, 0, token.LastBlock, token.Synced, err } // set the current holders into the provider and get the new ones - if err := provider.SetLastBalances(ctx, []byte(token.ExternalID), currentHolders, token.LastBlock); err != nil { + if err := provider.SetLastBalances(ctx, []byte(token.ExternalID), + currentHolders, token.LastBlock, + ); err != nil { return nil, 0, token.LastBlock, token.Synced, err } return provider.HoldersBalances(ctx, []byte(token.ExternalID), token.LastBlock) From d7dd71299949222c4c43990a38cb76c38a111e5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Fri, 26 Jan 2024 13:03:22 +0100 Subject: [PATCH 13/35] missing comments for gitcoin and poap providers and fixed logs levels for some traces --- scanner/providers/gitcoin/gitcoin.go | 62 ++++++++++++++++++++++--- scanner/providers/poap/poap_provider.go | 31 +++++++++++-- 2 files changed, 82 insertions(+), 11 deletions(-) diff --git a/scanner/providers/gitcoin/gitcoin.go b/scanner/providers/gitcoin/gitcoin.go index c86d554c..cc215869 100644 --- a/scanner/providers/gitcoin/gitcoin.go +++ b/scanner/providers/gitcoin/gitcoin.go @@ -20,8 +20,9 @@ import ( ) const ( - dateLayout = "2006-01-02T15:04:05.999Z" - hexAddress = "0x000000000000000000000000000000000000006C" + dateLayout = "2006-01-02T15:04:05.999Z" + hexAddress = "0x000000000000000000000000000000000000006C" + defaultCooldown = time.Hour * 6 ) type gitcoinScoreResult struct { @@ -55,11 +56,20 @@ type GitcoinPassportConf struct { Cooldown time.Duration } +// Init initializes the Gitcoin Passport provider with the given config. If the +// config is not of type GitcoinPassportConf, or the API endpoint is missing, it +// returns an error. If the cooldown is not set, it defaults to 6 hours. func (g *GitcoinPassport) Init(iconf any) error { conf, ok := iconf.(GitcoinPassportConf) if !ok { return fmt.Errorf("invalid config type") } + if conf.APIEndpoint == "" { + return fmt.Errorf("missing API endpoint") + } + if conf.Cooldown == 0 { + conf.Cooldown = defaultCooldown + } g.apiEndpoint = conf.APIEndpoint g.cooldown = conf.Cooldown // init download variables @@ -77,22 +87,31 @@ func (g *GitcoinPassport) Init(iconf any) error { return nil } +// SetRef is not implemented for Gitcoin Passport. func (g *GitcoinPassport) SetRef(_ any) error { return nil } +// SetLastBalances stores the balances of the last block (or other kind of +// reference). It is used to calculate the partial balances of the current +// block. func (g *GitcoinPassport) SetLastBalances(_ context.Context, _ []byte, balances map[common.Address]*big.Int, _ uint64, ) error { - log.Infof("setting last balances for %d addresses", len(balances)) g.currentBalancesMtx.Lock() defer g.currentBalancesMtx.Unlock() for addr, balance := range balances { g.currentBalances[addr] = new(big.Int).Set(balance) } + log.Debugw("last balances stored", "balances", len(balances)) return nil } +// HoldersBalances returns the balances of the Gitcoin Passport holders. If the +// cooldown time has passed, it starts a new download. If the download is +// finished, it returns the partial balances of the current block and the last +// block scanned. If the download is not finished or the cooldown time has not +// passed, it returns nil balances (no changes). func (g *GitcoinPassport) HoldersBalances(_ context.Context, _ []byte, _ uint64) ( map[common.Address]*big.Int, uint64, uint64, bool, error, ) { @@ -129,6 +148,8 @@ func (g *GitcoinPassport) HoldersBalances(_ context.Context, _ []byte, _ uint64) return nil, 1, lastUpdateID, true, nil } +// updateBalances downloads the json from the API endpoint and stores the +// balances in the newBalances variable. It also stores the last update time. func (g *GitcoinPassport) updateBalances() error { // download de json from API endpoint req, err := http.NewRequestWithContext(g.ctx, http.MethodGet, g.apiEndpoint, nil) @@ -147,7 +168,9 @@ func (g *GitcoinPassport) updateBalances() error { if res.StatusCode != http.StatusOK { return fmt.Errorf("error downloading json: %s", res.Status) } - log.Infof("downloading json from %s (%d bytes)...", g.apiEndpoint, res.ContentLength) + log.Debugw("downloading json from gitcoin endpoint", + "endpoin", g.apiEndpoint, + "size", res.ContentLength) // some vars to track progress bytesRead := 0 iterations := 0 @@ -161,7 +184,7 @@ func (g *GitcoinPassport) updateBalances() error { bytesRead += len(scanner.Bytes()) if iterations++; iterations%10000 == 0 { progress := float64(bytesRead) / float64(res.ContentLength) * 100 - log.Infow("still downloading Gitcoin Passport balances...", + log.Debugw("still downloading Gitcoin Passport balances...", "progress", fmt.Sprintf("%.2f", progress), "elapsed", time.Since(elapsed).Seconds()) } @@ -203,61 +226,79 @@ func (g *GitcoinPassport) updateBalances() error { return nil } +// Close cancels the download context. func (g *GitcoinPassport) Close() error { g.cancel() return nil } +// IsExternal returns true because Gitcoin Passport is an external provider. func (g *GitcoinPassport) IsExternal() bool { return true } +// IsSynced returns true if the balances are not empty. func (g *GitcoinPassport) IsSynced(_ []byte) bool { g.currentBalancesMtx.RLock() defer g.currentBalancesMtx.RUnlock() return len(g.currentBalances) > 0 } +// Address returns the address of the Gitcoin Passport contract. func (g *GitcoinPassport) Address() common.Address { return common.HexToAddress(hexAddress) } +// Type returns the type of the Gitcoin Passport contract. func (g *GitcoinPassport) Type() uint64 { return providers.CONTRACT_TYPE_GITCOIN } +// ChainID returns the chain ID of the Gitcoin Passport contract. func (g *GitcoinPassport) ChainID() uint64 { return 1 } +// Name returns the name of the Gitcoin Passport contract. func (g *GitcoinPassport) Name(_ []byte) (string, error) { return "Gitcoin Passport Score", nil } +// Symbol returns the symbol of the Gitcoin Passport contract. func (g *GitcoinPassport) Symbol(_ []byte) (string, error) { return "GPS", nil } +// Decimals is not implemented for Gitcoin Passport. func (g *GitcoinPassport) Decimals(_ []byte) (uint64, error) { return 0, nil } +// TotalSupply is not implemented for Gitcoin Passport. func (g *GitcoinPassport) TotalSupply(_ []byte) (*big.Int, error) { return big.NewInt(0), nil } +// BalanceOf is not implemented for Gitcoin Passport. func (g *GitcoinPassport) BalanceOf(_ common.Address, _ []byte) (*big.Int, error) { return big.NewInt(0), nil } +// BalanceAt is not implemented for Gitcoin Passport. func (g *GitcoinPassport) BalanceAt(_ context.Context, _ common.Address, _ []byte, _ uint64) (*big.Int, error) { return big.NewInt(0), nil } +// BlockTimestamp returns the timestamp of the last update of the balances. func (g *GitcoinPassport) BlockTimestamp(_ context.Context, _ uint64) (string, error) { - return fmt.Sprint(time.Now()), nil + lastUpdate, ok := g.lastUpdate.Load().(time.Time) + if !ok { + return "", fmt.Errorf("error getting last update") + } + return fmt.Sprint(lastUpdate), nil } +// BlockNumber returns the block number of the last update of the balances. func (g *GitcoinPassport) BlockRootHash(_ context.Context, _ uint64) ([]byte, error) { lastUpdate, ok := g.lastUpdate.Load().(time.Time) if !ok { @@ -267,14 +308,21 @@ func (g *GitcoinPassport) BlockRootHash(_ context.Context, _ uint64) ([]byte, er return timeHash[:], nil } +// BlockNumber returns the block number of the last update of the balances. func (g *GitcoinPassport) LatestBlockNumber(_ context.Context, _ []byte) (uint64, error) { - return uint64(time.Now().Unix() / 60), nil + lastUpdate, ok := g.lastUpdate.Load().(time.Time) + if !ok { + return 0, fmt.Errorf("error getting last update") + } + return uint64(lastUpdate.Unix() / 60), nil } +// CreationBlock is not implemented for Gitcoin Passport. func (g *GitcoinPassport) CreationBlock(_ context.Context, _ []byte) (uint64, error) { return 1, nil } +// IconURI is not implemented for Gitcoin Passport. func (g *GitcoinPassport) IconURI(_ []byte) (string, error) { return "", nil } diff --git a/scanner/providers/poap/poap_provider.go b/scanner/providers/poap/poap_provider.go index 4d97d033..eaff0d96 100644 --- a/scanner/providers/poap/poap_provider.go +++ b/scanner/providers/poap/poap_provider.go @@ -72,10 +72,6 @@ type POAPConfig struct { AccessToken string } -func (p *POAPHolderProvider) IsSynced(_ []byte) bool { - return true -} - // Init initializes the POAP external provider with the database provided. // It returns an error if the POAP access token or api endpoint uri is not // defined. @@ -99,6 +95,8 @@ func (p *POAPHolderProvider) Init(iconf any) error { return nil } +// SetRef method is not implemented in the POAP external provider. By default it +// returns nil error. func (p *POAPHolderProvider) SetRef(_ any) error { return nil } @@ -114,6 +112,7 @@ func (p *POAPHolderProvider) SetLastBalances(_ context.Context, id []byte, from: from, snapshot: balances, } + log.Debugw("last balances stored", "balances", len(balances)) return nil } @@ -126,6 +125,7 @@ func (p *POAPHolderProvider) HoldersBalances(_ context.Context, id []byte, delta ) { // parse eventID from id eventID := string(id) + log.Infow("getting POAP holders balances", "eventID", eventID) // get last snapshot newSnapshot, err := p.lastHolders(eventID) if err != nil { @@ -156,22 +156,38 @@ func (p *POAPHolderProvider) Close() error { return nil } +// IsExternal method returns true because the POAP provider is an external +// provider. func (p *POAPHolderProvider) IsExternal() bool { return true } +// IsSynced returns true if the POAP external provider has a snapshot for the +// given id. +func (p *POAPHolderProvider) IsSynced(externalID []byte) bool { + _, exist := p.snapshots[string(externalID)] + return exist +} + +// Address returns the address of the POAP token. func (p *POAPHolderProvider) Address() common.Address { return common.HexToAddress(POAP_CONTRACT_ADDRESS) } +// Type returns the type of the POAP token. By default it returns the +// CONTRACT_TYPE_POAP. func (p *POAPHolderProvider) Type() uint64 { return providers.CONTRACT_TYPE_POAP } +// ChainID method is not implemented in the POAP external provider. By default 1. func (p *POAPHolderProvider) ChainID() uint64 { return 1 } +// Name returns the name of the POAP token. It makes a request to the POAP API +// endpoint to get the event info for the eventID provided and returns the name +// of the event. func (p *POAPHolderProvider) Name(id []byte) (string, error) { info, err := p.getEventInfo(string(id)) if err != nil { @@ -180,6 +196,10 @@ func (p *POAPHolderProvider) Name(id []byte) (string, error) { return info.Name, nil } +// Symbol returns the symbol of the POAP token. It makes a request to the POAP +// API endpoint to get the event info for the eventID provided and returns the +// symbol of the event, which is composed by the prefix POAP_SYMBOL_PREFIX and +// the fancyID of the event. func (p *POAPHolderProvider) Symbol(id []byte) (string, error) { info, err := p.getEventInfo(string(id)) if err != nil { @@ -249,6 +269,9 @@ func (p *POAPHolderProvider) CreationBlock(_ context.Context, _ []byte) (uint64, return 0, nil } +// IconURI returns the icon uri for the given id. It makes a request to the POAP +// API endpoint to get the event info for the eventID provided and returns the +// icon uri. func (p *POAPHolderProvider) IconURI(id []byte) (string, error) { info, err := p.getEventInfo(string(id)) if err != nil { From 64bdfa01f0a5bb1e1b0b4fba7670ff8303f0ae2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Fri, 26 Jan 2024 14:12:16 +0100 Subject: [PATCH 14/35] poap tests with mocked api --- cmd/census3/main.go | 2 +- .../{gitcoin.go => gitcoin_provider.go} | 2 +- ...tcoin_test.go => gitcoin_provider_test.go} | 29 +++------ scanner/providers/helpers.go | 46 ++++++++++++++ scanner/providers/poap/mocked_data.json | 15 +++++ .../providers/poap/mocked_data_updated.json | 13 ++++ scanner/providers/poap/poap_provider.go | 20 +++--- scanner/providers/poap/poap_provider_test.go | 63 +++++++++++++++++++ 8 files changed, 158 insertions(+), 32 deletions(-) rename scanner/providers/gitcoin/{gitcoin.go => gitcoin_provider.go} (99%) rename scanner/providers/gitcoin/{gitcoin_test.go => gitcoin_provider_test.go} (77%) create mode 100644 scanner/providers/poap/mocked_data.json create mode 100644 scanner/providers/poap/mocked_data_updated.json diff --git a/cmd/census3/main.go b/cmd/census3/main.go index 5dc9edff..6faab0c1 100644 --- a/cmd/census3/main.go +++ b/cmd/census3/main.go @@ -162,7 +162,7 @@ func main() { if config.poapAPIEndpoint != "" { poapProvider := new(poap.POAPHolderProvider) if err := poapProvider.Init(poap.POAPConfig{ - URI: config.poapAPIEndpoint, + APIEndpoint: config.poapAPIEndpoint, AccessToken: config.poapAuthToken, }); err != nil { log.Fatal(err) diff --git a/scanner/providers/gitcoin/gitcoin.go b/scanner/providers/gitcoin/gitcoin_provider.go similarity index 99% rename from scanner/providers/gitcoin/gitcoin.go rename to scanner/providers/gitcoin/gitcoin_provider.go index cc215869..eec1647d 100644 --- a/scanner/providers/gitcoin/gitcoin.go +++ b/scanner/providers/gitcoin/gitcoin_provider.go @@ -126,7 +126,6 @@ func (g *GitcoinPassport) HoldersBalances(_ context.Context, _ []byte, _ uint64) defer g.downloading.Store(false) if err := g.updateBalances(); err != nil { - fmt.Println(err) log.Warnw("Error updating Gitcoin Passport balances", "err", err) return } @@ -207,6 +206,7 @@ func (g *GitcoinPassport) updateBalances() error { } if lastUpdate, exists := lastBalancesUpdates[addr]; !exists || date.After(lastUpdate) { balances[addr] = big.NewInt(int64(fBalance)) + lastBalancesUpdates[addr] = date } } } diff --git a/scanner/providers/gitcoin/gitcoin_test.go b/scanner/providers/gitcoin/gitcoin_provider_test.go similarity index 77% rename from scanner/providers/gitcoin/gitcoin_test.go rename to scanner/providers/gitcoin/gitcoin_provider_test.go index cd3cd51f..02c8f813 100644 --- a/scanner/providers/gitcoin/gitcoin_test.go +++ b/scanner/providers/gitcoin/gitcoin_provider_test.go @@ -2,15 +2,14 @@ package gitcoin import ( "context" - "fmt" "math/big" - "net/http" "strings" "testing" "time" "github.com/ethereum/go-ethereum/common" qt "github.com/frankban/quicktest" + "github.com/vocdoni/census3/scanner/providers" ) var ( @@ -25,28 +24,18 @@ var ( } ) -func serveStaticFile(original, updated string) (string, string) { - http.HandleFunc("/original", func(w http.ResponseWriter, r *http.Request) { - http.ServeFile(w, r, original) - }) - http.HandleFunc("/updated", func(w http.ResponseWriter, r *http.Request) { - http.ServeFile(w, r, updated) - }) - go func() { - if err := http.ListenAndServe(":8080", nil); err != nil { - fmt.Println("HTTP server error:", err) - } - }() - return "http://localhost:8080/original", "http://localhost:8080/updated" -} - func TestGitcoinPassport(t *testing.T) { c := qt.New(t) // start the mocked server with the static file - originalEndpoint, updatedEndpoint := serveStaticFile("./mocked_data.jsonl", "./mocked_data_updated.jsonl") + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + endpoints := providers.ServeTestStaticFiles(ctx, 5500, map[string]string{ + "/original": "./mocked_data.jsonl", + "/updated": "./mocked_data_updated.jsonl", + }) // create the provider provider := new(GitcoinPassport) - c.Assert(provider.Init(GitcoinPassportConf{originalEndpoint, time.Second * 2}), qt.IsNil) + c.Assert(provider.Init(GitcoinPassportConf{endpoints["/original"], time.Second * 2}), qt.IsNil) // start the first download emptyBalances, _, _, _, err := provider.HoldersBalances(context.TODO(), nil, 0) c.Assert(err, qt.IsNil) @@ -69,7 +58,7 @@ func TestGitcoinPassport(t *testing.T) { // empty results because the data the same c.Assert(len(sameBalances), qt.Equals, 0) - provider.apiEndpoint = updatedEndpoint + provider.apiEndpoint = endpoints["/updated"] provider.lastUpdate.Store(time.Time{}) emptyBalances, _, _, _, err = provider.HoldersBalances(context.TODO(), nil, 0) c.Assert(err, qt.IsNil) diff --git a/scanner/providers/helpers.go b/scanner/providers/helpers.go index addf8e4a..503f7b5a 100644 --- a/scanner/providers/helpers.go +++ b/scanner/providers/helpers.go @@ -1,9 +1,15 @@ package providers import ( + "context" + "fmt" "math/big" + "net/http" + "strings" + "time" "github.com/ethereum/go-ethereum/common" + "go.vocdoni.io/dvote/log" ) // CalcPartialHolders calculates the partial holders from the current and new holders @@ -45,3 +51,43 @@ func CalcPartialHolders(currentHolders, newHolders map[common.Address]*big.Int) } return partialHolders } + +// ServeTestStaticFiles serves the given files in the given port and returns a +// map with the URIs of the served files. The server is shutdown when the given +// context is done. It is useful for testing external providers to emulate +// external API services. +func ServeTestStaticFiles(ctx context.Context, port int, files map[string]string) map[string]string { + srv := &http.Server{Addr: fmt.Sprintf(":%d", port)} + // iterate over the files and serve them storing the URIs in a map + uris := map[string]string{} + for path := range files { + uris[path] = fmt.Sprintf("http://localhost:%d%s", port, path) + } + // serve the files + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + for path, file := range files { + currentFile := file + if strings.HasPrefix(r.URL.Path, path) { + http.ServeFile(w, r, currentFile) + return + } + } + }) + // run the server in a goroutine + go func() { + if err := srv.ListenAndServe(); err != http.ErrServerClosed { + log.Errorf("HTTP server error: %v", err) + } + }() + // shutdown the server when the context is done in a goroutine + go func() { + <-ctx.Done() + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := srv.Shutdown(shutdownCtx); err != nil { + log.Errorf("HTTP server error: %v", err) + } + }() + // return the URIs + return uris +} diff --git a/scanner/providers/poap/mocked_data.json b/scanner/providers/poap/mocked_data.json new file mode 100644 index 00000000..aac28c3b --- /dev/null +++ b/scanner/providers/poap/mocked_data.json @@ -0,0 +1,15 @@ +{ + "total": 10, + "tokens": [ + {"owner": { "id": "0x1" }}, + {"owner": { "id": "0x2" }}, + {"owner": { "id": "0x3" }}, + {"owner": { "id": "0x4" }}, + {"owner": { "id": "0x5" }}, + {"owner": { "id": "0x6" }}, + {"owner": { "id": "0x7" }}, + {"owner": { "id": "0x8" }}, + {"owner": { "id": "0x9" }}, + {"owner": { "id": "0x10" }} + ] +} \ No newline at end of file diff --git a/scanner/providers/poap/mocked_data_updated.json b/scanner/providers/poap/mocked_data_updated.json new file mode 100644 index 00000000..38fb63d9 --- /dev/null +++ b/scanner/providers/poap/mocked_data_updated.json @@ -0,0 +1,13 @@ +{ + "total": 8, + "tokens": [ + {"owner": { "id": "0x3" }}, + {"owner": { "id": "0x4" }}, + {"owner": { "id": "0x5" }}, + {"owner": { "id": "0x6" }}, + {"owner": { "id": "0x7" }}, + {"owner": { "id": "0x8" }}, + {"owner": { "id": "0x9" }}, + {"owner": { "id": "0x10" }} + ] +} \ No newline at end of file diff --git a/scanner/providers/poap/poap_provider.go b/scanner/providers/poap/poap_provider.go index eaff0d96..36ce8694 100644 --- a/scanner/providers/poap/poap_provider.go +++ b/scanner/providers/poap/poap_provider.go @@ -61,14 +61,14 @@ type POAPSnapshot struct { // POAP API to get the list of POAPs for an event ID and calculate the balances // of the token holders from the last snapshot. type POAPHolderProvider struct { - URI string - AccessToken string + apiEndpoint string + accessToken string snapshots map[string]*POAPSnapshot snapshotsMtx *sync.RWMutex } type POAPConfig struct { - URI string + APIEndpoint string AccessToken string } @@ -82,14 +82,14 @@ func (p *POAPHolderProvider) Init(iconf any) error { return fmt.Errorf("bad config type, it must be a POAPConfig struct") } - if conf.URI == "" { + if conf.APIEndpoint == "" { return fmt.Errorf("no POAP URI defined") } if conf.AccessToken == "" { return fmt.Errorf("no POAP access token defined") } - p.URI = conf.URI - p.AccessToken = conf.AccessToken + p.apiEndpoint = conf.APIEndpoint + p.accessToken = conf.AccessToken p.snapshots = make(map[string]*POAPSnapshot) p.snapshotsMtx = &sync.RWMutex{} return nil @@ -313,7 +313,7 @@ func (p *POAPHolderProvider) lastHolders(eventID string) (map[common.Address]*bi // list contains the address of the token holder. func (p *POAPHolderProvider) holdersPage(eventID string, offset int) (*POAPAPIResponse, error) { // compose the endpoint for the request - strURL, err := url.JoinPath(p.URI, fmt.Sprintf(POAP_URI, eventID)) + strURL, err := url.JoinPath(p.apiEndpoint, fmt.Sprintf(POAP_URI, eventID)) if err != nil { return nil, err } @@ -331,7 +331,7 @@ func (p *POAPHolderProvider) holdersPage(eventID string, offset int) (*POAPAPIRe return nil, err } req.Header.Add("accept", "application/json") - req.Header.Add("x-api-key", p.AccessToken) + req.Header.Add("x-api-key", p.accessToken) // do the request res, err := http.DefaultClient.Do(req) if err != nil { @@ -360,7 +360,7 @@ func (p *POAPHolderProvider) holdersPage(eventID string, offset int) (*POAPAPIRe // returns an EventAPIResponse struct with the event info. func (p *POAPHolderProvider) getEventInfo(eventID string) (*EventAPIResponse, error) { // compose the endpoint for the request - strURL, err := url.JoinPath(p.URI, fmt.Sprintf(EVENT_URI, eventID)) + strURL, err := url.JoinPath(p.apiEndpoint, fmt.Sprintf(EVENT_URI, eventID)) if err != nil { return nil, err } @@ -374,7 +374,7 @@ func (p *POAPHolderProvider) getEventInfo(eventID string) (*EventAPIResponse, er return nil, err } req.Header.Add("accept", "application/json") - req.Header.Add("x-api-key", p.AccessToken) + req.Header.Add("x-api-key", p.accessToken) // do the request res, err := http.DefaultClient.Do(req) if err != nil { diff --git a/scanner/providers/poap/poap_provider_test.go b/scanner/providers/poap/poap_provider_test.go index c420335c..709897a0 100644 --- a/scanner/providers/poap/poap_provider_test.go +++ b/scanner/providers/poap/poap_provider_test.go @@ -1 +1,64 @@ package poap + +import ( + "context" + "testing" + + qt "github.com/frankban/quicktest" + "github.com/vocdoni/census3/scanner/providers" +) + +var ( + expectedOriginalHolders = map[string]string{ + "0x0000000000000000000000000000000000000001": "1", + "0x0000000000000000000000000000000000000002": "1", + "0x0000000000000000000000000000000000000003": "1", + "0x0000000000000000000000000000000000000004": "1", + "0x0000000000000000000000000000000000000005": "1", + "0x0000000000000000000000000000000000000006": "1", + "0x0000000000000000000000000000000000000007": "1", + "0x0000000000000000000000000000000000000008": "1", + "0x0000000000000000000000000000000000000009": "1", + "0x0000000000000000000000000000000000000010": "1", + } + expectedUpdatedHolders = map[string]string{ + "0x0000000000000000000000000000000000000001": "-1", + "0x0000000000000000000000000000000000000002": "-1", + } +) + +func TestPOAP(t *testing.T) { + c := qt.New(t) + // start the mocked server with the static file + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + endpoints := providers.ServeTestStaticFiles(ctx, 5501, map[string]string{ + "/original": "./mocked_data.json", + "/updated": "./mocked_data_updated.json", + }) + + provider := new(POAPHolderProvider) + c.Assert(provider.Init(POAPConfig{endpoints["/original"], "no-token"}), qt.IsNil) + holders, _, _, _, err := provider.HoldersBalances(context.TODO(), nil, 0) + c.Assert(err, qt.IsNil) + c.Assert(len(holders), qt.Equals, len(expectedOriginalHolders)) + for addr, balance := range holders { + expectedBalance, exists := expectedOriginalHolders[addr.Hex()] + c.Assert(exists, qt.Equals, true) + c.Assert(balance.String(), qt.Equals, expectedBalance) + } + sameBalances, _, _, _, err := provider.HoldersBalances(context.TODO(), nil, 0) + c.Assert(err, qt.IsNil) + // empty results because the data the same + c.Assert(len(sameBalances), qt.Equals, 0) + + provider.apiEndpoint = endpoints["/updated"] + holders, _, _, _, err = provider.HoldersBalances(context.TODO(), nil, 0) + c.Assert(err, qt.IsNil) + c.Assert(len(holders), qt.Equals, len(expectedUpdatedHolders)) + for addr, balance := range holders { + expectedBalance, exists := expectedUpdatedHolders[addr.Hex()] + c.Assert(exists, qt.Equals, true) + c.Assert(balance.String(), qt.Equals, expectedBalance) + } +} From 57c2e51f63fbff8e86c88c8972f5ffe5331d0341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Fri, 26 Jan 2024 16:34:28 +0100 Subject: [PATCH 15/35] some packages moved to internal package, old contracts abi and code removed --- api/api.go | 2 +- api/censuses.go | 2 +- api/helpers.go | 4 +- api/strategies.go | 6 +- api/tokens.go | 2 +- contracts/README.md | 4 +- contracts/aragon/want/want.abi | 1 - contracts/aragon/want/want.go | 1816 ---------- contracts/nation3/vestedToken/veNation.abi | 1 - contracts/nation3/vestedToken/veNation.go | 2204 ------------ contracts/poap/poap.abi | 960 ------ contracts/poap/poap.go | 3072 ----------------- {lexer => internal/lexer}/consts.go | 0 {lexer => internal/lexer}/eval.go | 0 {lexer => internal/lexer}/eval_test.go | 0 {lexer => internal/lexer}/example_test.go | 0 {lexer => internal/lexer}/lexer.go | 0 {lexer => internal/lexer}/lexer_test.go | 0 {lexer => internal/lexer}/token.go | 0 {lexer => internal/lexer}/token_test.go | 0 {queue => internal/queue}/queue.go | 0 {queue => internal/queue}/queue_test.go | 0 .../roundedcensus}/roundedcensus.go | 0 .../roundedcensus}/roundedcensus_test.go | 0 .../strategyoperators}/combinators.go | 0 .../strategyoperators}/combinators_test.go | 0 .../strategyoperators}/operators.go | 2 +- .../strategyoperators}/operators_test.go | 2 +- .../strategyoperators}/strategyoperators.go | 2 +- .../strategyoperators_test.go | 0 30 files changed, 13 insertions(+), 8067 deletions(-) delete mode 100644 contracts/aragon/want/want.abi delete mode 100644 contracts/aragon/want/want.go delete mode 100644 contracts/nation3/vestedToken/veNation.abi delete mode 100644 contracts/nation3/vestedToken/veNation.go delete mode 100644 contracts/poap/poap.abi delete mode 100644 contracts/poap/poap.go rename {lexer => internal/lexer}/consts.go (100%) rename {lexer => internal/lexer}/eval.go (100%) rename {lexer => internal/lexer}/eval_test.go (100%) rename {lexer => internal/lexer}/example_test.go (100%) rename {lexer => internal/lexer}/lexer.go (100%) rename {lexer => internal/lexer}/lexer_test.go (100%) rename {lexer => internal/lexer}/token.go (100%) rename {lexer => internal/lexer}/token_test.go (100%) rename {queue => internal/queue}/queue.go (100%) rename {queue => internal/queue}/queue_test.go (100%) rename {roundedcensus => internal/roundedcensus}/roundedcensus.go (100%) rename {roundedcensus => internal/roundedcensus}/roundedcensus_test.go (100%) rename {strategyoperators => internal/strategyoperators}/combinators.go (100%) rename {strategyoperators => internal/strategyoperators}/combinators_test.go (100%) rename {strategyoperators => internal/strategyoperators}/operators.go (99%) rename {strategyoperators => internal/strategyoperators}/operators_test.go (99%) rename {strategyoperators => internal/strategyoperators}/strategyoperators.go (99%) rename {strategyoperators => internal/strategyoperators}/strategyoperators_test.go (100%) diff --git a/api/api.go b/api/api.go index ad2abfa1..c8b5dc55 100644 --- a/api/api.go +++ b/api/api.go @@ -15,7 +15,7 @@ import ( "github.com/vocdoni/census3/db" "github.com/vocdoni/census3/db/annotations" queries "github.com/vocdoni/census3/db/sqlc" - "github.com/vocdoni/census3/queue" + "github.com/vocdoni/census3/internal/queue" "github.com/vocdoni/census3/scanner/providers" "github.com/vocdoni/census3/scanner/providers/web3" "go.vocdoni.io/dvote/api/censusdb" diff --git a/api/censuses.go b/api/censuses.go index de40f7b5..1f5e11bc 100644 --- a/api/censuses.go +++ b/api/censuses.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common" queries "github.com/vocdoni/census3/db/sqlc" "github.com/vocdoni/census3/internal" - "github.com/vocdoni/census3/roundedcensus" + "github.com/vocdoni/census3/internal/roundedcensus" "go.vocdoni.io/dvote/httprouter" api "go.vocdoni.io/dvote/httprouter/apirest" "go.vocdoni.io/dvote/log" diff --git a/api/helpers.go b/api/helpers.go index 60e88b53..61ff777d 100644 --- a/api/helpers.go +++ b/api/helpers.go @@ -13,10 +13,10 @@ import ( "github.com/ethereum/go-ethereum/common" queries "github.com/vocdoni/census3/db/sqlc" - "github.com/vocdoni/census3/lexer" + "github.com/vocdoni/census3/internal/lexer" + "github.com/vocdoni/census3/internal/strategyoperators" "github.com/vocdoni/census3/scanner/providers" "github.com/vocdoni/census3/scanner/providers/web3" - "github.com/vocdoni/census3/strategyoperators" "go.vocdoni.io/dvote/api/censusdb" "go.vocdoni.io/dvote/censustree" storagelayer "go.vocdoni.io/dvote/data" diff --git a/api/strategies.go b/api/strategies.go index 83bca999..a06db20c 100644 --- a/api/strategies.go +++ b/api/strategies.go @@ -13,9 +13,9 @@ import ( gocid "github.com/ipfs/go-cid" queries "github.com/vocdoni/census3/db/sqlc" "github.com/vocdoni/census3/internal" - "github.com/vocdoni/census3/lexer" - "github.com/vocdoni/census3/roundedcensus" - "github.com/vocdoni/census3/strategyoperators" + "github.com/vocdoni/census3/internal/lexer" + "github.com/vocdoni/census3/internal/roundedcensus" + "github.com/vocdoni/census3/internal/strategyoperators" "go.vocdoni.io/dvote/httprouter" api "go.vocdoni.io/dvote/httprouter/apirest" "go.vocdoni.io/dvote/log" diff --git a/api/tokens.go b/api/tokens.go index a364ed59..488614e7 100644 --- a/api/tokens.go +++ b/api/tokens.go @@ -14,7 +14,7 @@ import ( "github.com/vocdoni/census3/db/annotations" queries "github.com/vocdoni/census3/db/sqlc" "github.com/vocdoni/census3/internal" - "github.com/vocdoni/census3/lexer" + "github.com/vocdoni/census3/internal/lexer" "github.com/vocdoni/census3/scanner/providers" "github.com/vocdoni/census3/scanner/providers/web3" "go.vocdoni.io/dvote/httprouter" diff --git a/contracts/README.md b/contracts/README.md index 8382c132..c988abb9 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -2,5 +2,5 @@ This directory contains the contracts ABI and the GoLang bindings for all supported tokens. For adding a new token: - 1. Add the ABI (i.e Copy the ABI from Etherscan) - 2. Generate the GoLang bindings using `abigen` tool (see bindContract.sh) +1. Add the ABI (i.e Copy the ABI from Etherscan) +2. Generate the GoLang bindings using `abigen` tool (see bindContract.sh) diff --git a/contracts/aragon/want/want.abi b/contracts/aragon/want/want.abi deleted file mode 100644 index b6897c5c..00000000 --- a/contracts/aragon/want/want.abi +++ /dev/null @@ -1 +0,0 @@ -[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_blockNumber","type":"uint256"}],"name":"balanceOfAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_depositedToken","type":"address"},{"name":"_name","type":"string"},{"name":"_symbol","type":"string"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_blockNumber","type":"uint256"}],"name":"totalSupplyAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"depositedToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"entity","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"entity","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}] \ No newline at end of file diff --git a/contracts/aragon/want/want.go b/contracts/aragon/want/want.go deleted file mode 100644 index 6046c246..00000000 --- a/contracts/aragon/want/want.go +++ /dev/null @@ -1,1816 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package AragonWrappedANTTokenContract - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// AragonWrappedANTTokenContractMetaData contains all meta data concerning the AragonWrappedANTTokenContract contract. -var AragonWrappedANTTokenContractMetaData = &bind.MetaData{ - ABI: "[{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"hasInitialized\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"\",\"type\":\"address\"},{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"\",\"type\":\"address\"},{\"name\":\"\",\"type\":\"address\"},{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_script\",\"type\":\"bytes\"}],\"name\":\"getEVMScriptExecutor\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getRecoveryVault\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_blockNumber\",\"type\":\"uint256\"}],\"name\":\"balanceOfAt\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_token\",\"type\":\"address\"}],\"name\":\"allowRecoverability\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"appId\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getInitializationBlock\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_depositedToken\",\"type\":\"address\"},{\"name\":\"_name\",\"type\":\"string\"},{\"name\":\"_symbol\",\"type\":\"string\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_blockNumber\",\"type\":\"uint256\"}],\"name\":\"totalSupplyAt\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_token\",\"type\":\"address\"}],\"name\":\"transferToVault\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_sender\",\"type\":\"address\"},{\"name\":\"_role\",\"type\":\"bytes32\"},{\"name\":\"_params\",\"type\":\"uint256[]\"}],\"name\":\"canPerform\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getEVMScriptRegistry\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"\",\"type\":\"address\"},{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"kernel\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"depositedToken\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"},{\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isPetrified\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"entity\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"entity\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"executor\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"script\",\"type\":\"bytes\"},{\"indexed\":false,\"name\":\"input\",\"type\":\"bytes\"},{\"indexed\":false,\"name\":\"returnData\",\"type\":\"bytes\"}],\"name\":\"ScriptResult\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"vault\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RecoverToVault\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"}]", -} - -// AragonWrappedANTTokenContractABI is the input ABI used to generate the binding from. -// Deprecated: Use AragonWrappedANTTokenContractMetaData.ABI instead. -var AragonWrappedANTTokenContractABI = AragonWrappedANTTokenContractMetaData.ABI - -// AragonWrappedANTTokenContract is an auto generated Go binding around an Ethereum contract. -type AragonWrappedANTTokenContract struct { - AragonWrappedANTTokenContractCaller // Read-only binding to the contract - AragonWrappedANTTokenContractTransactor // Write-only binding to the contract - AragonWrappedANTTokenContractFilterer // Log filterer for contract events -} - -// AragonWrappedANTTokenContractCaller is an auto generated read-only Go binding around an Ethereum contract. -type AragonWrappedANTTokenContractCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// AragonWrappedANTTokenContractTransactor is an auto generated write-only Go binding around an Ethereum contract. -type AragonWrappedANTTokenContractTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// AragonWrappedANTTokenContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type AragonWrappedANTTokenContractFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// AragonWrappedANTTokenContractSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type AragonWrappedANTTokenContractSession struct { - Contract *AragonWrappedANTTokenContract // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// AragonWrappedANTTokenContractCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type AragonWrappedANTTokenContractCallerSession struct { - Contract *AragonWrappedANTTokenContractCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// AragonWrappedANTTokenContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type AragonWrappedANTTokenContractTransactorSession struct { - Contract *AragonWrappedANTTokenContractTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// AragonWrappedANTTokenContractRaw is an auto generated low-level Go binding around an Ethereum contract. -type AragonWrappedANTTokenContractRaw struct { - Contract *AragonWrappedANTTokenContract // Generic contract binding to access the raw methods on -} - -// AragonWrappedANTTokenContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type AragonWrappedANTTokenContractCallerRaw struct { - Contract *AragonWrappedANTTokenContractCaller // Generic read-only contract binding to access the raw methods on -} - -// AragonWrappedANTTokenContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type AragonWrappedANTTokenContractTransactorRaw struct { - Contract *AragonWrappedANTTokenContractTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewAragonWrappedANTTokenContract creates a new instance of AragonWrappedANTTokenContract, bound to a specific deployed contract. -func NewAragonWrappedANTTokenContract(address common.Address, backend bind.ContractBackend) (*AragonWrappedANTTokenContract, error) { - contract, err := bindAragonWrappedANTTokenContract(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &AragonWrappedANTTokenContract{AragonWrappedANTTokenContractCaller: AragonWrappedANTTokenContractCaller{contract: contract}, AragonWrappedANTTokenContractTransactor: AragonWrappedANTTokenContractTransactor{contract: contract}, AragonWrappedANTTokenContractFilterer: AragonWrappedANTTokenContractFilterer{contract: contract}}, nil -} - -// NewAragonWrappedANTTokenContractCaller creates a new read-only instance of AragonWrappedANTTokenContract, bound to a specific deployed contract. -func NewAragonWrappedANTTokenContractCaller(address common.Address, caller bind.ContractCaller) (*AragonWrappedANTTokenContractCaller, error) { - contract, err := bindAragonWrappedANTTokenContract(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &AragonWrappedANTTokenContractCaller{contract: contract}, nil -} - -// NewAragonWrappedANTTokenContractTransactor creates a new write-only instance of AragonWrappedANTTokenContract, bound to a specific deployed contract. -func NewAragonWrappedANTTokenContractTransactor(address common.Address, transactor bind.ContractTransactor) (*AragonWrappedANTTokenContractTransactor, error) { - contract, err := bindAragonWrappedANTTokenContract(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &AragonWrappedANTTokenContractTransactor{contract: contract}, nil -} - -// NewAragonWrappedANTTokenContractFilterer creates a new log filterer instance of AragonWrappedANTTokenContract, bound to a specific deployed contract. -func NewAragonWrappedANTTokenContractFilterer(address common.Address, filterer bind.ContractFilterer) (*AragonWrappedANTTokenContractFilterer, error) { - contract, err := bindAragonWrappedANTTokenContract(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &AragonWrappedANTTokenContractFilterer{contract: contract}, nil -} - -// bindAragonWrappedANTTokenContract binds a generic wrapper to an already deployed contract. -func bindAragonWrappedANTTokenContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := AragonWrappedANTTokenContractMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _AragonWrappedANTTokenContract.Contract.AragonWrappedANTTokenContractCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.AragonWrappedANTTokenContractTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.AragonWrappedANTTokenContractTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _AragonWrappedANTTokenContract.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.contract.Transact(opts, method, params...) -} - -// AllowRecoverability is a free data retrieval call binding the contract method 0x7e7db6e1. -// -// Solidity: function allowRecoverability(address _token) view returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) AllowRecoverability(opts *bind.CallOpts, _token common.Address) (bool, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "allowRecoverability", _token) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// AllowRecoverability is a free data retrieval call binding the contract method 0x7e7db6e1. -// -// Solidity: function allowRecoverability(address _token) view returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) AllowRecoverability(_token common.Address) (bool, error) { - return _AragonWrappedANTTokenContract.Contract.AllowRecoverability(&_AragonWrappedANTTokenContract.CallOpts, _token) -} - -// AllowRecoverability is a free data retrieval call binding the contract method 0x7e7db6e1. -// -// Solidity: function allowRecoverability(address _token) view returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) AllowRecoverability(_token common.Address) (bool, error) { - return _AragonWrappedANTTokenContract.Contract.AllowRecoverability(&_AragonWrappedANTTokenContract.CallOpts, _token) -} - -// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. -// -// Solidity: function allowance(address , address ) view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) Allowance(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address) (*big.Int, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "allowance", arg0, arg1) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. -// -// Solidity: function allowance(address , address ) view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) Allowance(arg0 common.Address, arg1 common.Address) (*big.Int, error) { - return _AragonWrappedANTTokenContract.Contract.Allowance(&_AragonWrappedANTTokenContract.CallOpts, arg0, arg1) -} - -// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. -// -// Solidity: function allowance(address , address ) view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) Allowance(arg0 common.Address, arg1 common.Address) (*big.Int, error) { - return _AragonWrappedANTTokenContract.Contract.Allowance(&_AragonWrappedANTTokenContract.CallOpts, arg0, arg1) -} - -// AppId is a free data retrieval call binding the contract method 0x80afdea8. -// -// Solidity: function appId() view returns(bytes32) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) AppId(opts *bind.CallOpts) ([32]byte, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "appId") - - if err != nil { - return *new([32]byte), err - } - - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - - return out0, err - -} - -// AppId is a free data retrieval call binding the contract method 0x80afdea8. -// -// Solidity: function appId() view returns(bytes32) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) AppId() ([32]byte, error) { - return _AragonWrappedANTTokenContract.Contract.AppId(&_AragonWrappedANTTokenContract.CallOpts) -} - -// AppId is a free data retrieval call binding the contract method 0x80afdea8. -// -// Solidity: function appId() view returns(bytes32) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) AppId() ([32]byte, error) { - return _AragonWrappedANTTokenContract.Contract.AppId(&_AragonWrappedANTTokenContract.CallOpts) -} - -// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. -// -// Solidity: function balanceOf(address _owner) view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) BalanceOf(opts *bind.CallOpts, _owner common.Address) (*big.Int, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "balanceOf", _owner) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. -// -// Solidity: function balanceOf(address _owner) view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) BalanceOf(_owner common.Address) (*big.Int, error) { - return _AragonWrappedANTTokenContract.Contract.BalanceOf(&_AragonWrappedANTTokenContract.CallOpts, _owner) -} - -// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. -// -// Solidity: function balanceOf(address _owner) view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) BalanceOf(_owner common.Address) (*big.Int, error) { - return _AragonWrappedANTTokenContract.Contract.BalanceOf(&_AragonWrappedANTTokenContract.CallOpts, _owner) -} - -// BalanceOfAt is a free data retrieval call binding the contract method 0x4ee2cd7e. -// -// Solidity: function balanceOfAt(address _owner, uint256 _blockNumber) view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) BalanceOfAt(opts *bind.CallOpts, _owner common.Address, _blockNumber *big.Int) (*big.Int, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "balanceOfAt", _owner, _blockNumber) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// BalanceOfAt is a free data retrieval call binding the contract method 0x4ee2cd7e. -// -// Solidity: function balanceOfAt(address _owner, uint256 _blockNumber) view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) BalanceOfAt(_owner common.Address, _blockNumber *big.Int) (*big.Int, error) { - return _AragonWrappedANTTokenContract.Contract.BalanceOfAt(&_AragonWrappedANTTokenContract.CallOpts, _owner, _blockNumber) -} - -// BalanceOfAt is a free data retrieval call binding the contract method 0x4ee2cd7e. -// -// Solidity: function balanceOfAt(address _owner, uint256 _blockNumber) view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) BalanceOfAt(_owner common.Address, _blockNumber *big.Int) (*big.Int, error) { - return _AragonWrappedANTTokenContract.Contract.BalanceOfAt(&_AragonWrappedANTTokenContract.CallOpts, _owner, _blockNumber) -} - -// CanPerform is a free data retrieval call binding the contract method 0xa1658fad. -// -// Solidity: function canPerform(address _sender, bytes32 _role, uint256[] _params) view returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) CanPerform(opts *bind.CallOpts, _sender common.Address, _role [32]byte, _params []*big.Int) (bool, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "canPerform", _sender, _role, _params) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// CanPerform is a free data retrieval call binding the contract method 0xa1658fad. -// -// Solidity: function canPerform(address _sender, bytes32 _role, uint256[] _params) view returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) CanPerform(_sender common.Address, _role [32]byte, _params []*big.Int) (bool, error) { - return _AragonWrappedANTTokenContract.Contract.CanPerform(&_AragonWrappedANTTokenContract.CallOpts, _sender, _role, _params) -} - -// CanPerform is a free data retrieval call binding the contract method 0xa1658fad. -// -// Solidity: function canPerform(address _sender, bytes32 _role, uint256[] _params) view returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) CanPerform(_sender common.Address, _role [32]byte, _params []*big.Int) (bool, error) { - return _AragonWrappedANTTokenContract.Contract.CanPerform(&_AragonWrappedANTTokenContract.CallOpts, _sender, _role, _params) -} - -// Decimals is a free data retrieval call binding the contract method 0x313ce567. -// -// Solidity: function decimals() view returns(uint8) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) Decimals(opts *bind.CallOpts) (uint8, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "decimals") - - if err != nil { - return *new(uint8), err - } - - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - -} - -// Decimals is a free data retrieval call binding the contract method 0x313ce567. -// -// Solidity: function decimals() view returns(uint8) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) Decimals() (uint8, error) { - return _AragonWrappedANTTokenContract.Contract.Decimals(&_AragonWrappedANTTokenContract.CallOpts) -} - -// Decimals is a free data retrieval call binding the contract method 0x313ce567. -// -// Solidity: function decimals() view returns(uint8) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) Decimals() (uint8, error) { - return _AragonWrappedANTTokenContract.Contract.Decimals(&_AragonWrappedANTTokenContract.CallOpts) -} - -// DepositedToken is a free data retrieval call binding the contract method 0xdad9b086. -// -// Solidity: function depositedToken() view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) DepositedToken(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "depositedToken") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// DepositedToken is a free data retrieval call binding the contract method 0xdad9b086. -// -// Solidity: function depositedToken() view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) DepositedToken() (common.Address, error) { - return _AragonWrappedANTTokenContract.Contract.DepositedToken(&_AragonWrappedANTTokenContract.CallOpts) -} - -// DepositedToken is a free data retrieval call binding the contract method 0xdad9b086. -// -// Solidity: function depositedToken() view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) DepositedToken() (common.Address, error) { - return _AragonWrappedANTTokenContract.Contract.DepositedToken(&_AragonWrappedANTTokenContract.CallOpts) -} - -// GetEVMScriptExecutor is a free data retrieval call binding the contract method 0x2914b9bd. -// -// Solidity: function getEVMScriptExecutor(bytes _script) view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) GetEVMScriptExecutor(opts *bind.CallOpts, _script []byte) (common.Address, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "getEVMScriptExecutor", _script) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// GetEVMScriptExecutor is a free data retrieval call binding the contract method 0x2914b9bd. -// -// Solidity: function getEVMScriptExecutor(bytes _script) view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) GetEVMScriptExecutor(_script []byte) (common.Address, error) { - return _AragonWrappedANTTokenContract.Contract.GetEVMScriptExecutor(&_AragonWrappedANTTokenContract.CallOpts, _script) -} - -// GetEVMScriptExecutor is a free data retrieval call binding the contract method 0x2914b9bd. -// -// Solidity: function getEVMScriptExecutor(bytes _script) view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) GetEVMScriptExecutor(_script []byte) (common.Address, error) { - return _AragonWrappedANTTokenContract.Contract.GetEVMScriptExecutor(&_AragonWrappedANTTokenContract.CallOpts, _script) -} - -// GetEVMScriptRegistry is a free data retrieval call binding the contract method 0xa479e508. -// -// Solidity: function getEVMScriptRegistry() view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) GetEVMScriptRegistry(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "getEVMScriptRegistry") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// GetEVMScriptRegistry is a free data retrieval call binding the contract method 0xa479e508. -// -// Solidity: function getEVMScriptRegistry() view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) GetEVMScriptRegistry() (common.Address, error) { - return _AragonWrappedANTTokenContract.Contract.GetEVMScriptRegistry(&_AragonWrappedANTTokenContract.CallOpts) -} - -// GetEVMScriptRegistry is a free data retrieval call binding the contract method 0xa479e508. -// -// Solidity: function getEVMScriptRegistry() view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) GetEVMScriptRegistry() (common.Address, error) { - return _AragonWrappedANTTokenContract.Contract.GetEVMScriptRegistry(&_AragonWrappedANTTokenContract.CallOpts) -} - -// GetInitializationBlock is a free data retrieval call binding the contract method 0x8b3dd749. -// -// Solidity: function getInitializationBlock() view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) GetInitializationBlock(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "getInitializationBlock") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetInitializationBlock is a free data retrieval call binding the contract method 0x8b3dd749. -// -// Solidity: function getInitializationBlock() view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) GetInitializationBlock() (*big.Int, error) { - return _AragonWrappedANTTokenContract.Contract.GetInitializationBlock(&_AragonWrappedANTTokenContract.CallOpts) -} - -// GetInitializationBlock is a free data retrieval call binding the contract method 0x8b3dd749. -// -// Solidity: function getInitializationBlock() view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) GetInitializationBlock() (*big.Int, error) { - return _AragonWrappedANTTokenContract.Contract.GetInitializationBlock(&_AragonWrappedANTTokenContract.CallOpts) -} - -// GetRecoveryVault is a free data retrieval call binding the contract method 0x32f0a3b5. -// -// Solidity: function getRecoveryVault() view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) GetRecoveryVault(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "getRecoveryVault") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// GetRecoveryVault is a free data retrieval call binding the contract method 0x32f0a3b5. -// -// Solidity: function getRecoveryVault() view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) GetRecoveryVault() (common.Address, error) { - return _AragonWrappedANTTokenContract.Contract.GetRecoveryVault(&_AragonWrappedANTTokenContract.CallOpts) -} - -// GetRecoveryVault is a free data retrieval call binding the contract method 0x32f0a3b5. -// -// Solidity: function getRecoveryVault() view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) GetRecoveryVault() (common.Address, error) { - return _AragonWrappedANTTokenContract.Contract.GetRecoveryVault(&_AragonWrappedANTTokenContract.CallOpts) -} - -// HasInitialized is a free data retrieval call binding the contract method 0x0803fac0. -// -// Solidity: function hasInitialized() view returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) HasInitialized(opts *bind.CallOpts) (bool, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "hasInitialized") - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// HasInitialized is a free data retrieval call binding the contract method 0x0803fac0. -// -// Solidity: function hasInitialized() view returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) HasInitialized() (bool, error) { - return _AragonWrappedANTTokenContract.Contract.HasInitialized(&_AragonWrappedANTTokenContract.CallOpts) -} - -// HasInitialized is a free data retrieval call binding the contract method 0x0803fac0. -// -// Solidity: function hasInitialized() view returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) HasInitialized() (bool, error) { - return _AragonWrappedANTTokenContract.Contract.HasInitialized(&_AragonWrappedANTTokenContract.CallOpts) -} - -// IsPetrified is a free data retrieval call binding the contract method 0xde4796ed. -// -// Solidity: function isPetrified() view returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) IsPetrified(opts *bind.CallOpts) (bool, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "isPetrified") - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsPetrified is a free data retrieval call binding the contract method 0xde4796ed. -// -// Solidity: function isPetrified() view returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) IsPetrified() (bool, error) { - return _AragonWrappedANTTokenContract.Contract.IsPetrified(&_AragonWrappedANTTokenContract.CallOpts) -} - -// IsPetrified is a free data retrieval call binding the contract method 0xde4796ed. -// -// Solidity: function isPetrified() view returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) IsPetrified() (bool, error) { - return _AragonWrappedANTTokenContract.Contract.IsPetrified(&_AragonWrappedANTTokenContract.CallOpts) -} - -// Kernel is a free data retrieval call binding the contract method 0xd4aae0c4. -// -// Solidity: function kernel() view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) Kernel(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "kernel") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Kernel is a free data retrieval call binding the contract method 0xd4aae0c4. -// -// Solidity: function kernel() view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) Kernel() (common.Address, error) { - return _AragonWrappedANTTokenContract.Contract.Kernel(&_AragonWrappedANTTokenContract.CallOpts) -} - -// Kernel is a free data retrieval call binding the contract method 0xd4aae0c4. -// -// Solidity: function kernel() view returns(address) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) Kernel() (common.Address, error) { - return _AragonWrappedANTTokenContract.Contract.Kernel(&_AragonWrappedANTTokenContract.CallOpts) -} - -// Name is a free data retrieval call binding the contract method 0x06fdde03. -// -// Solidity: function name() view returns(string) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) Name(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "name") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// Name is a free data retrieval call binding the contract method 0x06fdde03. -// -// Solidity: function name() view returns(string) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) Name() (string, error) { - return _AragonWrappedANTTokenContract.Contract.Name(&_AragonWrappedANTTokenContract.CallOpts) -} - -// Name is a free data retrieval call binding the contract method 0x06fdde03. -// -// Solidity: function name() view returns(string) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) Name() (string, error) { - return _AragonWrappedANTTokenContract.Contract.Name(&_AragonWrappedANTTokenContract.CallOpts) -} - -// Symbol is a free data retrieval call binding the contract method 0x95d89b41. -// -// Solidity: function symbol() view returns(string) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) Symbol(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "symbol") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// Symbol is a free data retrieval call binding the contract method 0x95d89b41. -// -// Solidity: function symbol() view returns(string) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) Symbol() (string, error) { - return _AragonWrappedANTTokenContract.Contract.Symbol(&_AragonWrappedANTTokenContract.CallOpts) -} - -// Symbol is a free data retrieval call binding the contract method 0x95d89b41. -// -// Solidity: function symbol() view returns(string) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) Symbol() (string, error) { - return _AragonWrappedANTTokenContract.Contract.Symbol(&_AragonWrappedANTTokenContract.CallOpts) -} - -// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. -// -// Solidity: function totalSupply() view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "totalSupply") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. -// -// Solidity: function totalSupply() view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) TotalSupply() (*big.Int, error) { - return _AragonWrappedANTTokenContract.Contract.TotalSupply(&_AragonWrappedANTTokenContract.CallOpts) -} - -// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. -// -// Solidity: function totalSupply() view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) TotalSupply() (*big.Int, error) { - return _AragonWrappedANTTokenContract.Contract.TotalSupply(&_AragonWrappedANTTokenContract.CallOpts) -} - -// TotalSupplyAt is a free data retrieval call binding the contract method 0x981b24d0. -// -// Solidity: function totalSupplyAt(uint256 _blockNumber) view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCaller) TotalSupplyAt(opts *bind.CallOpts, _blockNumber *big.Int) (*big.Int, error) { - var out []interface{} - err := _AragonWrappedANTTokenContract.contract.Call(opts, &out, "totalSupplyAt", _blockNumber) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// TotalSupplyAt is a free data retrieval call binding the contract method 0x981b24d0. -// -// Solidity: function totalSupplyAt(uint256 _blockNumber) view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) TotalSupplyAt(_blockNumber *big.Int) (*big.Int, error) { - return _AragonWrappedANTTokenContract.Contract.TotalSupplyAt(&_AragonWrappedANTTokenContract.CallOpts, _blockNumber) -} - -// TotalSupplyAt is a free data retrieval call binding the contract method 0x981b24d0. -// -// Solidity: function totalSupplyAt(uint256 _blockNumber) view returns(uint256) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractCallerSession) TotalSupplyAt(_blockNumber *big.Int) (*big.Int, error) { - return _AragonWrappedANTTokenContract.Contract.TotalSupplyAt(&_AragonWrappedANTTokenContract.CallOpts, _blockNumber) -} - -// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. -// -// Solidity: function approve(address , uint256 ) returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactor) Approve(opts *bind.TransactOpts, arg0 common.Address, arg1 *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.contract.Transact(opts, "approve", arg0, arg1) -} - -// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. -// -// Solidity: function approve(address , uint256 ) returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) Approve(arg0 common.Address, arg1 *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.Approve(&_AragonWrappedANTTokenContract.TransactOpts, arg0, arg1) -} - -// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. -// -// Solidity: function approve(address , uint256 ) returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactorSession) Approve(arg0 common.Address, arg1 *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.Approve(&_AragonWrappedANTTokenContract.TransactOpts, arg0, arg1) -} - -// Deposit is a paid mutator transaction binding the contract method 0xb6b55f25. -// -// Solidity: function deposit(uint256 _amount) returns() -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactor) Deposit(opts *bind.TransactOpts, _amount *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.contract.Transact(opts, "deposit", _amount) -} - -// Deposit is a paid mutator transaction binding the contract method 0xb6b55f25. -// -// Solidity: function deposit(uint256 _amount) returns() -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) Deposit(_amount *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.Deposit(&_AragonWrappedANTTokenContract.TransactOpts, _amount) -} - -// Deposit is a paid mutator transaction binding the contract method 0xb6b55f25. -// -// Solidity: function deposit(uint256 _amount) returns() -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactorSession) Deposit(_amount *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.Deposit(&_AragonWrappedANTTokenContract.TransactOpts, _amount) -} - -// Initialize is a paid mutator transaction binding the contract method 0x90657147. -// -// Solidity: function initialize(address _depositedToken, string _name, string _symbol) returns() -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactor) Initialize(opts *bind.TransactOpts, _depositedToken common.Address, _name string, _symbol string) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.contract.Transact(opts, "initialize", _depositedToken, _name, _symbol) -} - -// Initialize is a paid mutator transaction binding the contract method 0x90657147. -// -// Solidity: function initialize(address _depositedToken, string _name, string _symbol) returns() -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) Initialize(_depositedToken common.Address, _name string, _symbol string) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.Initialize(&_AragonWrappedANTTokenContract.TransactOpts, _depositedToken, _name, _symbol) -} - -// Initialize is a paid mutator transaction binding the contract method 0x90657147. -// -// Solidity: function initialize(address _depositedToken, string _name, string _symbol) returns() -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactorSession) Initialize(_depositedToken common.Address, _name string, _symbol string) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.Initialize(&_AragonWrappedANTTokenContract.TransactOpts, _depositedToken, _name, _symbol) -} - -// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. -// -// Solidity: function transfer(address , uint256 ) returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactor) Transfer(opts *bind.TransactOpts, arg0 common.Address, arg1 *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.contract.Transact(opts, "transfer", arg0, arg1) -} - -// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. -// -// Solidity: function transfer(address , uint256 ) returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) Transfer(arg0 common.Address, arg1 *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.Transfer(&_AragonWrappedANTTokenContract.TransactOpts, arg0, arg1) -} - -// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. -// -// Solidity: function transfer(address , uint256 ) returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactorSession) Transfer(arg0 common.Address, arg1 *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.Transfer(&_AragonWrappedANTTokenContract.TransactOpts, arg0, arg1) -} - -// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. -// -// Solidity: function transferFrom(address , address , uint256 ) returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactor) TransferFrom(opts *bind.TransactOpts, arg0 common.Address, arg1 common.Address, arg2 *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.contract.Transact(opts, "transferFrom", arg0, arg1, arg2) -} - -// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. -// -// Solidity: function transferFrom(address , address , uint256 ) returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) TransferFrom(arg0 common.Address, arg1 common.Address, arg2 *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.TransferFrom(&_AragonWrappedANTTokenContract.TransactOpts, arg0, arg1, arg2) -} - -// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. -// -// Solidity: function transferFrom(address , address , uint256 ) returns(bool) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactorSession) TransferFrom(arg0 common.Address, arg1 common.Address, arg2 *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.TransferFrom(&_AragonWrappedANTTokenContract.TransactOpts, arg0, arg1, arg2) -} - -// TransferToVault is a paid mutator transaction binding the contract method 0x9d4941d8. -// -// Solidity: function transferToVault(address _token) returns() -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactor) TransferToVault(opts *bind.TransactOpts, _token common.Address) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.contract.Transact(opts, "transferToVault", _token) -} - -// TransferToVault is a paid mutator transaction binding the contract method 0x9d4941d8. -// -// Solidity: function transferToVault(address _token) returns() -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) TransferToVault(_token common.Address) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.TransferToVault(&_AragonWrappedANTTokenContract.TransactOpts, _token) -} - -// TransferToVault is a paid mutator transaction binding the contract method 0x9d4941d8. -// -// Solidity: function transferToVault(address _token) returns() -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactorSession) TransferToVault(_token common.Address) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.TransferToVault(&_AragonWrappedANTTokenContract.TransactOpts, _token) -} - -// Withdraw is a paid mutator transaction binding the contract method 0x2e1a7d4d. -// -// Solidity: function withdraw(uint256 _amount) returns() -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactor) Withdraw(opts *bind.TransactOpts, _amount *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.contract.Transact(opts, "withdraw", _amount) -} - -// Withdraw is a paid mutator transaction binding the contract method 0x2e1a7d4d. -// -// Solidity: function withdraw(uint256 _amount) returns() -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractSession) Withdraw(_amount *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.Withdraw(&_AragonWrappedANTTokenContract.TransactOpts, _amount) -} - -// Withdraw is a paid mutator transaction binding the contract method 0x2e1a7d4d. -// -// Solidity: function withdraw(uint256 _amount) returns() -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractTransactorSession) Withdraw(_amount *big.Int) (*types.Transaction, error) { - return _AragonWrappedANTTokenContract.Contract.Withdraw(&_AragonWrappedANTTokenContract.TransactOpts, _amount) -} - -// AragonWrappedANTTokenContractApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the AragonWrappedANTTokenContract contract. -type AragonWrappedANTTokenContractApprovalIterator struct { - Event *AragonWrappedANTTokenContractApproval // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *AragonWrappedANTTokenContractApprovalIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(AragonWrappedANTTokenContractApproval) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(AragonWrappedANTTokenContractApproval) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *AragonWrappedANTTokenContractApprovalIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *AragonWrappedANTTokenContractApprovalIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// AragonWrappedANTTokenContractApproval represents a Approval event raised by the AragonWrappedANTTokenContract contract. -type AragonWrappedANTTokenContractApproval struct { - Owner common.Address - Spender common.Address - Value *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. -// -// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*AragonWrappedANTTokenContractApprovalIterator, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - var spenderRule []interface{} - for _, spenderItem := range spender { - spenderRule = append(spenderRule, spenderItem) - } - - logs, sub, err := _AragonWrappedANTTokenContract.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule) - if err != nil { - return nil, err - } - return &AragonWrappedANTTokenContractApprovalIterator{contract: _AragonWrappedANTTokenContract.contract, event: "Approval", logs: logs, sub: sub}, nil -} - -// WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. -// -// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *AragonWrappedANTTokenContractApproval, owner []common.Address, spender []common.Address) (event.Subscription, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - var spenderRule []interface{} - for _, spenderItem := range spender { - spenderRule = append(spenderRule, spenderItem) - } - - logs, sub, err := _AragonWrappedANTTokenContract.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(AragonWrappedANTTokenContractApproval) - if err := _AragonWrappedANTTokenContract.contract.UnpackLog(event, "Approval", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. -// -// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) ParseApproval(log types.Log) (*AragonWrappedANTTokenContractApproval, error) { - event := new(AragonWrappedANTTokenContractApproval) - if err := _AragonWrappedANTTokenContract.contract.UnpackLog(event, "Approval", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// AragonWrappedANTTokenContractDepositIterator is returned from FilterDeposit and is used to iterate over the raw logs and unpacked data for Deposit events raised by the AragonWrappedANTTokenContract contract. -type AragonWrappedANTTokenContractDepositIterator struct { - Event *AragonWrappedANTTokenContractDeposit // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *AragonWrappedANTTokenContractDepositIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(AragonWrappedANTTokenContractDeposit) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(AragonWrappedANTTokenContractDeposit) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *AragonWrappedANTTokenContractDepositIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *AragonWrappedANTTokenContractDepositIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// AragonWrappedANTTokenContractDeposit represents a Deposit event raised by the AragonWrappedANTTokenContract contract. -type AragonWrappedANTTokenContractDeposit struct { - Entity common.Address - Amount *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterDeposit is a free log retrieval operation binding the contract event 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c. -// -// Solidity: event Deposit(address indexed entity, uint256 amount) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) FilterDeposit(opts *bind.FilterOpts, entity []common.Address) (*AragonWrappedANTTokenContractDepositIterator, error) { - - var entityRule []interface{} - for _, entityItem := range entity { - entityRule = append(entityRule, entityItem) - } - - logs, sub, err := _AragonWrappedANTTokenContract.contract.FilterLogs(opts, "Deposit", entityRule) - if err != nil { - return nil, err - } - return &AragonWrappedANTTokenContractDepositIterator{contract: _AragonWrappedANTTokenContract.contract, event: "Deposit", logs: logs, sub: sub}, nil -} - -// WatchDeposit is a free log subscription operation binding the contract event 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c. -// -// Solidity: event Deposit(address indexed entity, uint256 amount) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) WatchDeposit(opts *bind.WatchOpts, sink chan<- *AragonWrappedANTTokenContractDeposit, entity []common.Address) (event.Subscription, error) { - - var entityRule []interface{} - for _, entityItem := range entity { - entityRule = append(entityRule, entityItem) - } - - logs, sub, err := _AragonWrappedANTTokenContract.contract.WatchLogs(opts, "Deposit", entityRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(AragonWrappedANTTokenContractDeposit) - if err := _AragonWrappedANTTokenContract.contract.UnpackLog(event, "Deposit", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseDeposit is a log parse operation binding the contract event 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c. -// -// Solidity: event Deposit(address indexed entity, uint256 amount) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) ParseDeposit(log types.Log) (*AragonWrappedANTTokenContractDeposit, error) { - event := new(AragonWrappedANTTokenContractDeposit) - if err := _AragonWrappedANTTokenContract.contract.UnpackLog(event, "Deposit", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// AragonWrappedANTTokenContractRecoverToVaultIterator is returned from FilterRecoverToVault and is used to iterate over the raw logs and unpacked data for RecoverToVault events raised by the AragonWrappedANTTokenContract contract. -type AragonWrappedANTTokenContractRecoverToVaultIterator struct { - Event *AragonWrappedANTTokenContractRecoverToVault // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *AragonWrappedANTTokenContractRecoverToVaultIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(AragonWrappedANTTokenContractRecoverToVault) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(AragonWrappedANTTokenContractRecoverToVault) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *AragonWrappedANTTokenContractRecoverToVaultIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *AragonWrappedANTTokenContractRecoverToVaultIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// AragonWrappedANTTokenContractRecoverToVault represents a RecoverToVault event raised by the AragonWrappedANTTokenContract contract. -type AragonWrappedANTTokenContractRecoverToVault struct { - Vault common.Address - Token common.Address - Amount *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterRecoverToVault is a free log retrieval operation binding the contract event 0x596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02. -// -// Solidity: event RecoverToVault(address indexed vault, address indexed token, uint256 amount) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) FilterRecoverToVault(opts *bind.FilterOpts, vault []common.Address, token []common.Address) (*AragonWrappedANTTokenContractRecoverToVaultIterator, error) { - - var vaultRule []interface{} - for _, vaultItem := range vault { - vaultRule = append(vaultRule, vaultItem) - } - var tokenRule []interface{} - for _, tokenItem := range token { - tokenRule = append(tokenRule, tokenItem) - } - - logs, sub, err := _AragonWrappedANTTokenContract.contract.FilterLogs(opts, "RecoverToVault", vaultRule, tokenRule) - if err != nil { - return nil, err - } - return &AragonWrappedANTTokenContractRecoverToVaultIterator{contract: _AragonWrappedANTTokenContract.contract, event: "RecoverToVault", logs: logs, sub: sub}, nil -} - -// WatchRecoverToVault is a free log subscription operation binding the contract event 0x596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02. -// -// Solidity: event RecoverToVault(address indexed vault, address indexed token, uint256 amount) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) WatchRecoverToVault(opts *bind.WatchOpts, sink chan<- *AragonWrappedANTTokenContractRecoverToVault, vault []common.Address, token []common.Address) (event.Subscription, error) { - - var vaultRule []interface{} - for _, vaultItem := range vault { - vaultRule = append(vaultRule, vaultItem) - } - var tokenRule []interface{} - for _, tokenItem := range token { - tokenRule = append(tokenRule, tokenItem) - } - - logs, sub, err := _AragonWrappedANTTokenContract.contract.WatchLogs(opts, "RecoverToVault", vaultRule, tokenRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(AragonWrappedANTTokenContractRecoverToVault) - if err := _AragonWrappedANTTokenContract.contract.UnpackLog(event, "RecoverToVault", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseRecoverToVault is a log parse operation binding the contract event 0x596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02. -// -// Solidity: event RecoverToVault(address indexed vault, address indexed token, uint256 amount) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) ParseRecoverToVault(log types.Log) (*AragonWrappedANTTokenContractRecoverToVault, error) { - event := new(AragonWrappedANTTokenContractRecoverToVault) - if err := _AragonWrappedANTTokenContract.contract.UnpackLog(event, "RecoverToVault", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// AragonWrappedANTTokenContractScriptResultIterator is returned from FilterScriptResult and is used to iterate over the raw logs and unpacked data for ScriptResult events raised by the AragonWrappedANTTokenContract contract. -type AragonWrappedANTTokenContractScriptResultIterator struct { - Event *AragonWrappedANTTokenContractScriptResult // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *AragonWrappedANTTokenContractScriptResultIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(AragonWrappedANTTokenContractScriptResult) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(AragonWrappedANTTokenContractScriptResult) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *AragonWrappedANTTokenContractScriptResultIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *AragonWrappedANTTokenContractScriptResultIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// AragonWrappedANTTokenContractScriptResult represents a ScriptResult event raised by the AragonWrappedANTTokenContract contract. -type AragonWrappedANTTokenContractScriptResult struct { - Executor common.Address - Script []byte - Input []byte - ReturnData []byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterScriptResult is a free log retrieval operation binding the contract event 0x5229a5dba83a54ae8cb5b51bdd6de9474cacbe9dd332f5185f3a4f4f2e3f4ad9. -// -// Solidity: event ScriptResult(address indexed executor, bytes script, bytes input, bytes returnData) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) FilterScriptResult(opts *bind.FilterOpts, executor []common.Address) (*AragonWrappedANTTokenContractScriptResultIterator, error) { - - var executorRule []interface{} - for _, executorItem := range executor { - executorRule = append(executorRule, executorItem) - } - - logs, sub, err := _AragonWrappedANTTokenContract.contract.FilterLogs(opts, "ScriptResult", executorRule) - if err != nil { - return nil, err - } - return &AragonWrappedANTTokenContractScriptResultIterator{contract: _AragonWrappedANTTokenContract.contract, event: "ScriptResult", logs: logs, sub: sub}, nil -} - -// WatchScriptResult is a free log subscription operation binding the contract event 0x5229a5dba83a54ae8cb5b51bdd6de9474cacbe9dd332f5185f3a4f4f2e3f4ad9. -// -// Solidity: event ScriptResult(address indexed executor, bytes script, bytes input, bytes returnData) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) WatchScriptResult(opts *bind.WatchOpts, sink chan<- *AragonWrappedANTTokenContractScriptResult, executor []common.Address) (event.Subscription, error) { - - var executorRule []interface{} - for _, executorItem := range executor { - executorRule = append(executorRule, executorItem) - } - - logs, sub, err := _AragonWrappedANTTokenContract.contract.WatchLogs(opts, "ScriptResult", executorRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(AragonWrappedANTTokenContractScriptResult) - if err := _AragonWrappedANTTokenContract.contract.UnpackLog(event, "ScriptResult", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseScriptResult is a log parse operation binding the contract event 0x5229a5dba83a54ae8cb5b51bdd6de9474cacbe9dd332f5185f3a4f4f2e3f4ad9. -// -// Solidity: event ScriptResult(address indexed executor, bytes script, bytes input, bytes returnData) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) ParseScriptResult(log types.Log) (*AragonWrappedANTTokenContractScriptResult, error) { - event := new(AragonWrappedANTTokenContractScriptResult) - if err := _AragonWrappedANTTokenContract.contract.UnpackLog(event, "ScriptResult", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// AragonWrappedANTTokenContractTransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the AragonWrappedANTTokenContract contract. -type AragonWrappedANTTokenContractTransferIterator struct { - Event *AragonWrappedANTTokenContractTransfer // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *AragonWrappedANTTokenContractTransferIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(AragonWrappedANTTokenContractTransfer) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(AragonWrappedANTTokenContractTransfer) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *AragonWrappedANTTokenContractTransferIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *AragonWrappedANTTokenContractTransferIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// AragonWrappedANTTokenContractTransfer represents a Transfer event raised by the AragonWrappedANTTokenContract contract. -type AragonWrappedANTTokenContractTransfer struct { - From common.Address - To common.Address - Value *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. -// -// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AragonWrappedANTTokenContractTransferIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _AragonWrappedANTTokenContract.contract.FilterLogs(opts, "Transfer", fromRule, toRule) - if err != nil { - return nil, err - } - return &AragonWrappedANTTokenContractTransferIterator{contract: _AragonWrappedANTTokenContract.contract, event: "Transfer", logs: logs, sub: sub}, nil -} - -// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. -// -// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *AragonWrappedANTTokenContractTransfer, from []common.Address, to []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _AragonWrappedANTTokenContract.contract.WatchLogs(opts, "Transfer", fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(AragonWrappedANTTokenContractTransfer) - if err := _AragonWrappedANTTokenContract.contract.UnpackLog(event, "Transfer", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. -// -// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) ParseTransfer(log types.Log) (*AragonWrappedANTTokenContractTransfer, error) { - event := new(AragonWrappedANTTokenContractTransfer) - if err := _AragonWrappedANTTokenContract.contract.UnpackLog(event, "Transfer", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// AragonWrappedANTTokenContractWithdrawalIterator is returned from FilterWithdrawal and is used to iterate over the raw logs and unpacked data for Withdrawal events raised by the AragonWrappedANTTokenContract contract. -type AragonWrappedANTTokenContractWithdrawalIterator struct { - Event *AragonWrappedANTTokenContractWithdrawal // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *AragonWrappedANTTokenContractWithdrawalIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(AragonWrappedANTTokenContractWithdrawal) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(AragonWrappedANTTokenContractWithdrawal) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *AragonWrappedANTTokenContractWithdrawalIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *AragonWrappedANTTokenContractWithdrawalIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// AragonWrappedANTTokenContractWithdrawal represents a Withdrawal event raised by the AragonWrappedANTTokenContract contract. -type AragonWrappedANTTokenContractWithdrawal struct { - Entity common.Address - Amount *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterWithdrawal is a free log retrieval operation binding the contract event 0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65. -// -// Solidity: event Withdrawal(address indexed entity, uint256 amount) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) FilterWithdrawal(opts *bind.FilterOpts, entity []common.Address) (*AragonWrappedANTTokenContractWithdrawalIterator, error) { - - var entityRule []interface{} - for _, entityItem := range entity { - entityRule = append(entityRule, entityItem) - } - - logs, sub, err := _AragonWrappedANTTokenContract.contract.FilterLogs(opts, "Withdrawal", entityRule) - if err != nil { - return nil, err - } - return &AragonWrappedANTTokenContractWithdrawalIterator{contract: _AragonWrappedANTTokenContract.contract, event: "Withdrawal", logs: logs, sub: sub}, nil -} - -// WatchWithdrawal is a free log subscription operation binding the contract event 0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65. -// -// Solidity: event Withdrawal(address indexed entity, uint256 amount) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) WatchWithdrawal(opts *bind.WatchOpts, sink chan<- *AragonWrappedANTTokenContractWithdrawal, entity []common.Address) (event.Subscription, error) { - - var entityRule []interface{} - for _, entityItem := range entity { - entityRule = append(entityRule, entityItem) - } - - logs, sub, err := _AragonWrappedANTTokenContract.contract.WatchLogs(opts, "Withdrawal", entityRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(AragonWrappedANTTokenContractWithdrawal) - if err := _AragonWrappedANTTokenContract.contract.UnpackLog(event, "Withdrawal", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseWithdrawal is a log parse operation binding the contract event 0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65. -// -// Solidity: event Withdrawal(address indexed entity, uint256 amount) -func (_AragonWrappedANTTokenContract *AragonWrappedANTTokenContractFilterer) ParseWithdrawal(log types.Log) (*AragonWrappedANTTokenContractWithdrawal, error) { - event := new(AragonWrappedANTTokenContractWithdrawal) - if err := _AragonWrappedANTTokenContract.contract.UnpackLog(event, "Withdrawal", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/contracts/nation3/vestedToken/veNation.abi b/contracts/nation3/vestedToken/veNation.abi deleted file mode 100644 index 700b3529..00000000 --- a/contracts/nation3/vestedToken/veNation.abi +++ /dev/null @@ -1 +0,0 @@ -[{"name":"CommitOwnership","inputs":[{"type":"address","name":"admin","indexed":false}],"anonymous":false,"type":"event"},{"name":"ApplyOwnership","inputs":[{"type":"address","name":"admin","indexed":false}],"anonymous":false,"type":"event"},{"name":"DepositsLockedChange","inputs":[{"type":"bool","name":"status","indexed":false}],"anonymous":false,"type":"event"},{"name":"Deposit","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256","name":"value","indexed":false},{"type":"uint256","name":"locktime","indexed":true},{"type":"int128","name":"type","indexed":false},{"type":"uint256","name":"ts","indexed":false}],"anonymous":false,"type":"event"},{"name":"Withdraw","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256","name":"value","indexed":false},{"type":"uint256","name":"ts","indexed":false}],"anonymous":false,"type":"event"},{"name":"Supply","inputs":[{"type":"uint256","name":"prevSupply","indexed":false},{"type":"uint256","name":"supply","indexed":false}],"anonymous":false,"type":"event"},{"outputs":[],"inputs":[{"type":"address","name":"token_addr"},{"type":"string","name":"_name"},{"type":"string","name":"_symbol"},{"type":"string","name":"_version"}],"stateMutability":"nonpayable","type":"constructor"},{"name":"commit_transfer_ownership","outputs":[],"inputs":[{"type":"address","name":"addr"}],"stateMutability":"nonpayable","type":"function","gas":37597},{"name":"set_depositsLocked","outputs":[],"inputs":[{"type":"bool","name":"new_status"}],"stateMutability":"nonpayable","type":"function","gas":37624},{"name":"apply_transfer_ownership","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":38527},{"name":"commit_smart_wallet_checker","outputs":[],"inputs":[{"type":"address","name":"addr"}],"stateMutability":"nonpayable","type":"function","gas":36337},{"name":"apply_smart_wallet_checker","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":37125},{"name":"get_last_user_slope","outputs":[{"type":"int128","name":""}],"inputs":[{"type":"address","name":"addr"}],"stateMutability":"view","type":"function","gas":2599},{"name":"user_point_history__ts","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"address","name":"_addr"},{"type":"uint256","name":"_idx"}],"stateMutability":"view","type":"function","gas":1702},{"name":"locked__end","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"address","name":"_addr"}],"stateMutability":"view","type":"function","gas":1623},{"name":"checkpoint","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":37052402},{"name":"deposit_for","outputs":[],"inputs":[{"type":"address","name":"_addr"},{"type":"uint256","name":"_value"}],"stateMutability":"nonpayable","type":"function","gas":74280011},{"name":"create_lock","outputs":[],"inputs":[{"type":"uint256","name":"_value"},{"type":"uint256","name":"_unlock_time"}],"stateMutability":"nonpayable","type":"function","gas":74281615},{"name":"increase_amount","outputs":[],"inputs":[{"type":"uint256","name":"_value"}],"stateMutability":"nonpayable","type":"function","gas":74280980},{"name":"increase_unlock_time","outputs":[],"inputs":[{"type":"uint256","name":"_unlock_time"}],"stateMutability":"nonpayable","type":"function","gas":74281728},{"name":"withdraw","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":37224478},{"name":"balanceOf","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"address","name":"addr"}],"stateMutability":"view","type":"function"},{"name":"balanceOf","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"address","name":"addr"},{"type":"uint256","name":"_t"}],"stateMutability":"view","type":"function"},{"name":"balanceOfAt","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"address","name":"addr"},{"type":"uint256","name":"_block"}],"stateMutability":"view","type":"function","gas":514393},{"name":"totalSupply","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function"},{"name":"totalSupply","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"t"}],"stateMutability":"view","type":"function"},{"name":"totalSupplyAt","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"_block"}],"stateMutability":"view","type":"function","gas":812650},{"name":"changeController","outputs":[],"inputs":[{"type":"address","name":"_newController"}],"stateMutability":"nonpayable","type":"function","gas":36937},{"name":"token","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":1871},{"name":"supply","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":1901},{"name":"locked","outputs":[{"type":"int128","name":"amount"},{"type":"uint256","name":"end"}],"inputs":[{"type":"address","name":"arg0"}],"stateMutability":"view","type":"function","gas":3389},{"name":"epoch","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":1961},{"name":"point_history","outputs":[{"type":"int128","name":"bias"},{"type":"int128","name":"slope"},{"type":"uint256","name":"ts"},{"type":"uint256","name":"blk"}],"inputs":[{"type":"uint256","name":"arg0"}],"stateMutability":"view","type":"function","gas":5580},{"name":"user_point_history","outputs":[{"type":"int128","name":"bias"},{"type":"int128","name":"slope"},{"type":"uint256","name":"ts"},{"type":"uint256","name":"blk"}],"inputs":[{"type":"address","name":"arg0"},{"type":"uint256","name":"arg1"}],"stateMutability":"view","type":"function","gas":6109},{"name":"user_point_epoch","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"address","name":"arg0"}],"stateMutability":"view","type":"function","gas":2205},{"name":"slope_changes","outputs":[{"type":"int128","name":""}],"inputs":[{"type":"uint256","name":"arg0"}],"stateMutability":"view","type":"function","gas":2196},{"name":"controller","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2111},{"name":"transfersEnabled","outputs":[{"type":"bool","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2141},{"name":"depositsLocked","outputs":[{"type":"bool","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2171},{"name":"name","outputs":[{"type":"string","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":8603},{"name":"symbol","outputs":[{"type":"string","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":7656},{"name":"version","outputs":[{"type":"string","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":7686},{"name":"decimals","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2291},{"name":"future_smart_wallet_checker","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2321},{"name":"smart_wallet_checker","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2351},{"name":"admin","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2381},{"name":"future_admin","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2411}] \ No newline at end of file diff --git a/contracts/nation3/vestedToken/veNation.go b/contracts/nation3/vestedToken/veNation.go deleted file mode 100644 index a4f3fb4d..00000000 --- a/contracts/nation3/vestedToken/veNation.go +++ /dev/null @@ -1,2204 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package Nation3VestedTokenContract - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// Nation3VestedTokenContractMetaData contains all meta data concerning the Nation3VestedTokenContract contract. -var Nation3VestedTokenContractMetaData = &bind.MetaData{ - ABI: "[{\"name\":\"CommitOwnership\",\"inputs\":[{\"type\":\"address\",\"name\":\"admin\",\"indexed\":false}],\"anonymous\":false,\"type\":\"event\"},{\"name\":\"ApplyOwnership\",\"inputs\":[{\"type\":\"address\",\"name\":\"admin\",\"indexed\":false}],\"anonymous\":false,\"type\":\"event\"},{\"name\":\"DepositsLockedChange\",\"inputs\":[{\"type\":\"bool\",\"name\":\"status\",\"indexed\":false}],\"anonymous\":false,\"type\":\"event\"},{\"name\":\"Deposit\",\"inputs\":[{\"type\":\"address\",\"name\":\"provider\",\"indexed\":true},{\"type\":\"uint256\",\"name\":\"value\",\"indexed\":false},{\"type\":\"uint256\",\"name\":\"locktime\",\"indexed\":true},{\"type\":\"int128\",\"name\":\"type\",\"indexed\":false},{\"type\":\"uint256\",\"name\":\"ts\",\"indexed\":false}],\"anonymous\":false,\"type\":\"event\"},{\"name\":\"Withdraw\",\"inputs\":[{\"type\":\"address\",\"name\":\"provider\",\"indexed\":true},{\"type\":\"uint256\",\"name\":\"value\",\"indexed\":false},{\"type\":\"uint256\",\"name\":\"ts\",\"indexed\":false}],\"anonymous\":false,\"type\":\"event\"},{\"name\":\"Supply\",\"inputs\":[{\"type\":\"uint256\",\"name\":\"prevSupply\",\"indexed\":false},{\"type\":\"uint256\",\"name\":\"supply\",\"indexed\":false}],\"anonymous\":false,\"type\":\"event\"},{\"outputs\":[],\"inputs\":[{\"type\":\"address\",\"name\":\"token_addr\"},{\"type\":\"string\",\"name\":\"_name\"},{\"type\":\"string\",\"name\":\"_symbol\"},{\"type\":\"string\",\"name\":\"_version\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"name\":\"commit_transfer_ownership\",\"outputs\":[],\"inputs\":[{\"type\":\"address\",\"name\":\"addr\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"gas\":37597},{\"name\":\"set_depositsLocked\",\"outputs\":[],\"inputs\":[{\"type\":\"bool\",\"name\":\"new_status\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"gas\":37624},{\"name\":\"apply_transfer_ownership\",\"outputs\":[],\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"gas\":38527},{\"name\":\"commit_smart_wallet_checker\",\"outputs\":[],\"inputs\":[{\"type\":\"address\",\"name\":\"addr\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"gas\":36337},{\"name\":\"apply_smart_wallet_checker\",\"outputs\":[],\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"gas\":37125},{\"name\":\"get_last_user_slope\",\"outputs\":[{\"type\":\"int128\",\"name\":\"\"}],\"inputs\":[{\"type\":\"address\",\"name\":\"addr\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":2599},{\"name\":\"user_point_history__ts\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"\"}],\"inputs\":[{\"type\":\"address\",\"name\":\"_addr\"},{\"type\":\"uint256\",\"name\":\"_idx\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":1702},{\"name\":\"locked__end\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"\"}],\"inputs\":[{\"type\":\"address\",\"name\":\"_addr\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":1623},{\"name\":\"checkpoint\",\"outputs\":[],\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"gas\":37052402},{\"name\":\"deposit_for\",\"outputs\":[],\"inputs\":[{\"type\":\"address\",\"name\":\"_addr\"},{\"type\":\"uint256\",\"name\":\"_value\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"gas\":74280011},{\"name\":\"create_lock\",\"outputs\":[],\"inputs\":[{\"type\":\"uint256\",\"name\":\"_value\"},{\"type\":\"uint256\",\"name\":\"_unlock_time\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"gas\":74281615},{\"name\":\"increase_amount\",\"outputs\":[],\"inputs\":[{\"type\":\"uint256\",\"name\":\"_value\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"gas\":74280980},{\"name\":\"increase_unlock_time\",\"outputs\":[],\"inputs\":[{\"type\":\"uint256\",\"name\":\"_unlock_time\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"gas\":74281728},{\"name\":\"withdraw\",\"outputs\":[],\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"gas\":37224478},{\"name\":\"balanceOf\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"\"}],\"inputs\":[{\"type\":\"address\",\"name\":\"addr\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"name\":\"balanceOf\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"\"}],\"inputs\":[{\"type\":\"address\",\"name\":\"addr\"},{\"type\":\"uint256\",\"name\":\"_t\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"name\":\"balanceOfAt\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"\"}],\"inputs\":[{\"type\":\"address\",\"name\":\"addr\"},{\"type\":\"uint256\",\"name\":\"_block\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":514393},{\"name\":\"totalSupply\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"name\":\"totalSupply\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"\"}],\"inputs\":[{\"type\":\"uint256\",\"name\":\"t\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"name\":\"totalSupplyAt\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"\"}],\"inputs\":[{\"type\":\"uint256\",\"name\":\"_block\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":812650},{\"name\":\"changeController\",\"outputs\":[],\"inputs\":[{\"type\":\"address\",\"name\":\"_newController\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"gas\":36937},{\"name\":\"token\",\"outputs\":[{\"type\":\"address\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":1871},{\"name\":\"supply\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":1901},{\"name\":\"locked\",\"outputs\":[{\"type\":\"int128\",\"name\":\"amount\"},{\"type\":\"uint256\",\"name\":\"end\"}],\"inputs\":[{\"type\":\"address\",\"name\":\"arg0\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":3389},{\"name\":\"epoch\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":1961},{\"name\":\"point_history\",\"outputs\":[{\"type\":\"int128\",\"name\":\"bias\"},{\"type\":\"int128\",\"name\":\"slope\"},{\"type\":\"uint256\",\"name\":\"ts\"},{\"type\":\"uint256\",\"name\":\"blk\"}],\"inputs\":[{\"type\":\"uint256\",\"name\":\"arg0\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":5580},{\"name\":\"user_point_history\",\"outputs\":[{\"type\":\"int128\",\"name\":\"bias\"},{\"type\":\"int128\",\"name\":\"slope\"},{\"type\":\"uint256\",\"name\":\"ts\"},{\"type\":\"uint256\",\"name\":\"blk\"}],\"inputs\":[{\"type\":\"address\",\"name\":\"arg0\"},{\"type\":\"uint256\",\"name\":\"arg1\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":6109},{\"name\":\"user_point_epoch\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"\"}],\"inputs\":[{\"type\":\"address\",\"name\":\"arg0\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":2205},{\"name\":\"slope_changes\",\"outputs\":[{\"type\":\"int128\",\"name\":\"\"}],\"inputs\":[{\"type\":\"uint256\",\"name\":\"arg0\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":2196},{\"name\":\"controller\",\"outputs\":[{\"type\":\"address\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":2111},{\"name\":\"transfersEnabled\",\"outputs\":[{\"type\":\"bool\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":2141},{\"name\":\"depositsLocked\",\"outputs\":[{\"type\":\"bool\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":2171},{\"name\":\"name\",\"outputs\":[{\"type\":\"string\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":8603},{\"name\":\"symbol\",\"outputs\":[{\"type\":\"string\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":7656},{\"name\":\"version\",\"outputs\":[{\"type\":\"string\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":7686},{\"name\":\"decimals\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":2291},{\"name\":\"future_smart_wallet_checker\",\"outputs\":[{\"type\":\"address\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":2321},{\"name\":\"smart_wallet_checker\",\"outputs\":[{\"type\":\"address\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":2351},{\"name\":\"admin\",\"outputs\":[{\"type\":\"address\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":2381},{\"name\":\"future_admin\",\"outputs\":[{\"type\":\"address\",\"name\":\"\"}],\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"gas\":2411}]", -} - -// Nation3VestedTokenContractABI is the input ABI used to generate the binding from. -// Deprecated: Use Nation3VestedTokenContractMetaData.ABI instead. -var Nation3VestedTokenContractABI = Nation3VestedTokenContractMetaData.ABI - -// Nation3VestedTokenContract is an auto generated Go binding around an Ethereum contract. -type Nation3VestedTokenContract struct { - Nation3VestedTokenContractCaller // Read-only binding to the contract - Nation3VestedTokenContractTransactor // Write-only binding to the contract - Nation3VestedTokenContractFilterer // Log filterer for contract events -} - -// Nation3VestedTokenContractCaller is an auto generated read-only Go binding around an Ethereum contract. -type Nation3VestedTokenContractCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// Nation3VestedTokenContractTransactor is an auto generated write-only Go binding around an Ethereum contract. -type Nation3VestedTokenContractTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// Nation3VestedTokenContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type Nation3VestedTokenContractFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// Nation3VestedTokenContractSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type Nation3VestedTokenContractSession struct { - Contract *Nation3VestedTokenContract // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// Nation3VestedTokenContractCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type Nation3VestedTokenContractCallerSession struct { - Contract *Nation3VestedTokenContractCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// Nation3VestedTokenContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type Nation3VestedTokenContractTransactorSession struct { - Contract *Nation3VestedTokenContractTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// Nation3VestedTokenContractRaw is an auto generated low-level Go binding around an Ethereum contract. -type Nation3VestedTokenContractRaw struct { - Contract *Nation3VestedTokenContract // Generic contract binding to access the raw methods on -} - -// Nation3VestedTokenContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type Nation3VestedTokenContractCallerRaw struct { - Contract *Nation3VestedTokenContractCaller // Generic read-only contract binding to access the raw methods on -} - -// Nation3VestedTokenContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type Nation3VestedTokenContractTransactorRaw struct { - Contract *Nation3VestedTokenContractTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewNation3VestedTokenContract creates a new instance of Nation3VestedTokenContract, bound to a specific deployed contract. -func NewNation3VestedTokenContract(address common.Address, backend bind.ContractBackend) (*Nation3VestedTokenContract, error) { - contract, err := bindNation3VestedTokenContract(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &Nation3VestedTokenContract{Nation3VestedTokenContractCaller: Nation3VestedTokenContractCaller{contract: contract}, Nation3VestedTokenContractTransactor: Nation3VestedTokenContractTransactor{contract: contract}, Nation3VestedTokenContractFilterer: Nation3VestedTokenContractFilterer{contract: contract}}, nil -} - -// NewNation3VestedTokenContractCaller creates a new read-only instance of Nation3VestedTokenContract, bound to a specific deployed contract. -func NewNation3VestedTokenContractCaller(address common.Address, caller bind.ContractCaller) (*Nation3VestedTokenContractCaller, error) { - contract, err := bindNation3VestedTokenContract(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &Nation3VestedTokenContractCaller{contract: contract}, nil -} - -// NewNation3VestedTokenContractTransactor creates a new write-only instance of Nation3VestedTokenContract, bound to a specific deployed contract. -func NewNation3VestedTokenContractTransactor(address common.Address, transactor bind.ContractTransactor) (*Nation3VestedTokenContractTransactor, error) { - contract, err := bindNation3VestedTokenContract(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &Nation3VestedTokenContractTransactor{contract: contract}, nil -} - -// NewNation3VestedTokenContractFilterer creates a new log filterer instance of Nation3VestedTokenContract, bound to a specific deployed contract. -func NewNation3VestedTokenContractFilterer(address common.Address, filterer bind.ContractFilterer) (*Nation3VestedTokenContractFilterer, error) { - contract, err := bindNation3VestedTokenContract(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &Nation3VestedTokenContractFilterer{contract: contract}, nil -} - -// bindNation3VestedTokenContract binds a generic wrapper to an already deployed contract. -func bindNation3VestedTokenContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := Nation3VestedTokenContractMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Nation3VestedTokenContract *Nation3VestedTokenContractRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _Nation3VestedTokenContract.Contract.Nation3VestedTokenContractCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Nation3VestedTokenContract *Nation3VestedTokenContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.Nation3VestedTokenContractTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Nation3VestedTokenContract *Nation3VestedTokenContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.Nation3VestedTokenContractTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _Nation3VestedTokenContract.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.contract.Transact(opts, method, params...) -} - -// Admin is a free data retrieval call binding the contract method 0xf851a440. -// -// Solidity: function admin() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) Admin(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "admin") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Admin is a free data retrieval call binding the contract method 0xf851a440. -// -// Solidity: function admin() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) Admin() (common.Address, error) { - return _Nation3VestedTokenContract.Contract.Admin(&_Nation3VestedTokenContract.CallOpts) -} - -// Admin is a free data retrieval call binding the contract method 0xf851a440. -// -// Solidity: function admin() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) Admin() (common.Address, error) { - return _Nation3VestedTokenContract.Contract.Admin(&_Nation3VestedTokenContract.CallOpts) -} - -// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. -// -// Solidity: function balanceOf(address addr) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) BalanceOf(opts *bind.CallOpts, addr common.Address) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "balanceOf", addr) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. -// -// Solidity: function balanceOf(address addr) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) BalanceOf(addr common.Address) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.BalanceOf(&_Nation3VestedTokenContract.CallOpts, addr) -} - -// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. -// -// Solidity: function balanceOf(address addr) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) BalanceOf(addr common.Address) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.BalanceOf(&_Nation3VestedTokenContract.CallOpts, addr) -} - -// BalanceOf0 is a free data retrieval call binding the contract method 0x00fdd58e. -// -// Solidity: function balanceOf(address addr, uint256 _t) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) BalanceOf0(opts *bind.CallOpts, addr common.Address, _t *big.Int) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "balanceOf0", addr, _t) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// BalanceOf0 is a free data retrieval call binding the contract method 0x00fdd58e. -// -// Solidity: function balanceOf(address addr, uint256 _t) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) BalanceOf0(addr common.Address, _t *big.Int) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.BalanceOf0(&_Nation3VestedTokenContract.CallOpts, addr, _t) -} - -// BalanceOf0 is a free data retrieval call binding the contract method 0x00fdd58e. -// -// Solidity: function balanceOf(address addr, uint256 _t) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) BalanceOf0(addr common.Address, _t *big.Int) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.BalanceOf0(&_Nation3VestedTokenContract.CallOpts, addr, _t) -} - -// BalanceOfAt is a free data retrieval call binding the contract method 0x4ee2cd7e. -// -// Solidity: function balanceOfAt(address addr, uint256 _block) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) BalanceOfAt(opts *bind.CallOpts, addr common.Address, _block *big.Int) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "balanceOfAt", addr, _block) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// BalanceOfAt is a free data retrieval call binding the contract method 0x4ee2cd7e. -// -// Solidity: function balanceOfAt(address addr, uint256 _block) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) BalanceOfAt(addr common.Address, _block *big.Int) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.BalanceOfAt(&_Nation3VestedTokenContract.CallOpts, addr, _block) -} - -// BalanceOfAt is a free data retrieval call binding the contract method 0x4ee2cd7e. -// -// Solidity: function balanceOfAt(address addr, uint256 _block) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) BalanceOfAt(addr common.Address, _block *big.Int) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.BalanceOfAt(&_Nation3VestedTokenContract.CallOpts, addr, _block) -} - -// Controller is a free data retrieval call binding the contract method 0xf77c4791. -// -// Solidity: function controller() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) Controller(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "controller") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Controller is a free data retrieval call binding the contract method 0xf77c4791. -// -// Solidity: function controller() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) Controller() (common.Address, error) { - return _Nation3VestedTokenContract.Contract.Controller(&_Nation3VestedTokenContract.CallOpts) -} - -// Controller is a free data retrieval call binding the contract method 0xf77c4791. -// -// Solidity: function controller() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) Controller() (common.Address, error) { - return _Nation3VestedTokenContract.Contract.Controller(&_Nation3VestedTokenContract.CallOpts) -} - -// Decimals is a free data retrieval call binding the contract method 0x313ce567. -// -// Solidity: function decimals() view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) Decimals(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "decimals") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Decimals is a free data retrieval call binding the contract method 0x313ce567. -// -// Solidity: function decimals() view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) Decimals() (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.Decimals(&_Nation3VestedTokenContract.CallOpts) -} - -// Decimals is a free data retrieval call binding the contract method 0x313ce567. -// -// Solidity: function decimals() view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) Decimals() (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.Decimals(&_Nation3VestedTokenContract.CallOpts) -} - -// DepositsLocked is a free data retrieval call binding the contract method 0xf60ab774. -// -// Solidity: function depositsLocked() view returns(bool) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) DepositsLocked(opts *bind.CallOpts) (bool, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "depositsLocked") - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// DepositsLocked is a free data retrieval call binding the contract method 0xf60ab774. -// -// Solidity: function depositsLocked() view returns(bool) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) DepositsLocked() (bool, error) { - return _Nation3VestedTokenContract.Contract.DepositsLocked(&_Nation3VestedTokenContract.CallOpts) -} - -// DepositsLocked is a free data retrieval call binding the contract method 0xf60ab774. -// -// Solidity: function depositsLocked() view returns(bool) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) DepositsLocked() (bool, error) { - return _Nation3VestedTokenContract.Contract.DepositsLocked(&_Nation3VestedTokenContract.CallOpts) -} - -// Epoch is a free data retrieval call binding the contract method 0x900cf0cf. -// -// Solidity: function epoch() view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) Epoch(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "epoch") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Epoch is a free data retrieval call binding the contract method 0x900cf0cf. -// -// Solidity: function epoch() view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) Epoch() (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.Epoch(&_Nation3VestedTokenContract.CallOpts) -} - -// Epoch is a free data retrieval call binding the contract method 0x900cf0cf. -// -// Solidity: function epoch() view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) Epoch() (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.Epoch(&_Nation3VestedTokenContract.CallOpts) -} - -// FutureAdmin is a free data retrieval call binding the contract method 0x17f7182a. -// -// Solidity: function future_admin() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) FutureAdmin(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "future_admin") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// FutureAdmin is a free data retrieval call binding the contract method 0x17f7182a. -// -// Solidity: function future_admin() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) FutureAdmin() (common.Address, error) { - return _Nation3VestedTokenContract.Contract.FutureAdmin(&_Nation3VestedTokenContract.CallOpts) -} - -// FutureAdmin is a free data retrieval call binding the contract method 0x17f7182a. -// -// Solidity: function future_admin() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) FutureAdmin() (common.Address, error) { - return _Nation3VestedTokenContract.Contract.FutureAdmin(&_Nation3VestedTokenContract.CallOpts) -} - -// FutureSmartWalletChecker is a free data retrieval call binding the contract method 0x8ff36fd1. -// -// Solidity: function future_smart_wallet_checker() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) FutureSmartWalletChecker(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "future_smart_wallet_checker") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// FutureSmartWalletChecker is a free data retrieval call binding the contract method 0x8ff36fd1. -// -// Solidity: function future_smart_wallet_checker() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) FutureSmartWalletChecker() (common.Address, error) { - return _Nation3VestedTokenContract.Contract.FutureSmartWalletChecker(&_Nation3VestedTokenContract.CallOpts) -} - -// FutureSmartWalletChecker is a free data retrieval call binding the contract method 0x8ff36fd1. -// -// Solidity: function future_smart_wallet_checker() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) FutureSmartWalletChecker() (common.Address, error) { - return _Nation3VestedTokenContract.Contract.FutureSmartWalletChecker(&_Nation3VestedTokenContract.CallOpts) -} - -// GetLastUserSlope is a free data retrieval call binding the contract method 0x7c74a174. -// -// Solidity: function get_last_user_slope(address addr) view returns(int128) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) GetLastUserSlope(opts *bind.CallOpts, addr common.Address) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "get_last_user_slope", addr) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetLastUserSlope is a free data retrieval call binding the contract method 0x7c74a174. -// -// Solidity: function get_last_user_slope(address addr) view returns(int128) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) GetLastUserSlope(addr common.Address) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.GetLastUserSlope(&_Nation3VestedTokenContract.CallOpts, addr) -} - -// GetLastUserSlope is a free data retrieval call binding the contract method 0x7c74a174. -// -// Solidity: function get_last_user_slope(address addr) view returns(int128) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) GetLastUserSlope(addr common.Address) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.GetLastUserSlope(&_Nation3VestedTokenContract.CallOpts, addr) -} - -// Locked is a free data retrieval call binding the contract method 0xcbf9fe5f. -// -// Solidity: function locked(address arg0) view returns(int128 amount, uint256 end) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) Locked(opts *bind.CallOpts, arg0 common.Address) (struct { - Amount *big.Int - End *big.Int -}, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "locked", arg0) - - outstruct := new(struct { - Amount *big.Int - End *big.Int - }) - if err != nil { - return *outstruct, err - } - - outstruct.Amount = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - outstruct.End = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - - return *outstruct, err - -} - -// Locked is a free data retrieval call binding the contract method 0xcbf9fe5f. -// -// Solidity: function locked(address arg0) view returns(int128 amount, uint256 end) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) Locked(arg0 common.Address) (struct { - Amount *big.Int - End *big.Int -}, error) { - return _Nation3VestedTokenContract.Contract.Locked(&_Nation3VestedTokenContract.CallOpts, arg0) -} - -// Locked is a free data retrieval call binding the contract method 0xcbf9fe5f. -// -// Solidity: function locked(address arg0) view returns(int128 amount, uint256 end) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) Locked(arg0 common.Address) (struct { - Amount *big.Int - End *big.Int -}, error) { - return _Nation3VestedTokenContract.Contract.Locked(&_Nation3VestedTokenContract.CallOpts, arg0) -} - -// LockedEnd is a free data retrieval call binding the contract method 0xadc63589. -// -// Solidity: function locked__end(address _addr) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) LockedEnd(opts *bind.CallOpts, _addr common.Address) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "locked__end", _addr) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// LockedEnd is a free data retrieval call binding the contract method 0xadc63589. -// -// Solidity: function locked__end(address _addr) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) LockedEnd(_addr common.Address) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.LockedEnd(&_Nation3VestedTokenContract.CallOpts, _addr) -} - -// LockedEnd is a free data retrieval call binding the contract method 0xadc63589. -// -// Solidity: function locked__end(address _addr) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) LockedEnd(_addr common.Address) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.LockedEnd(&_Nation3VestedTokenContract.CallOpts, _addr) -} - -// Name is a free data retrieval call binding the contract method 0x06fdde03. -// -// Solidity: function name() view returns(string) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) Name(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "name") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// Name is a free data retrieval call binding the contract method 0x06fdde03. -// -// Solidity: function name() view returns(string) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) Name() (string, error) { - return _Nation3VestedTokenContract.Contract.Name(&_Nation3VestedTokenContract.CallOpts) -} - -// Name is a free data retrieval call binding the contract method 0x06fdde03. -// -// Solidity: function name() view returns(string) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) Name() (string, error) { - return _Nation3VestedTokenContract.Contract.Name(&_Nation3VestedTokenContract.CallOpts) -} - -// PointHistory is a free data retrieval call binding the contract method 0xd1febfb9. -// -// Solidity: function point_history(uint256 arg0) view returns(int128 bias, int128 slope, uint256 ts, uint256 blk) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) PointHistory(opts *bind.CallOpts, arg0 *big.Int) (struct { - Bias *big.Int - Slope *big.Int - Ts *big.Int - Blk *big.Int -}, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "point_history", arg0) - - outstruct := new(struct { - Bias *big.Int - Slope *big.Int - Ts *big.Int - Blk *big.Int - }) - if err != nil { - return *outstruct, err - } - - outstruct.Bias = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - outstruct.Slope = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - outstruct.Ts = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) - outstruct.Blk = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) - - return *outstruct, err - -} - -// PointHistory is a free data retrieval call binding the contract method 0xd1febfb9. -// -// Solidity: function point_history(uint256 arg0) view returns(int128 bias, int128 slope, uint256 ts, uint256 blk) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) PointHistory(arg0 *big.Int) (struct { - Bias *big.Int - Slope *big.Int - Ts *big.Int - Blk *big.Int -}, error) { - return _Nation3VestedTokenContract.Contract.PointHistory(&_Nation3VestedTokenContract.CallOpts, arg0) -} - -// PointHistory is a free data retrieval call binding the contract method 0xd1febfb9. -// -// Solidity: function point_history(uint256 arg0) view returns(int128 bias, int128 slope, uint256 ts, uint256 blk) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) PointHistory(arg0 *big.Int) (struct { - Bias *big.Int - Slope *big.Int - Ts *big.Int - Blk *big.Int -}, error) { - return _Nation3VestedTokenContract.Contract.PointHistory(&_Nation3VestedTokenContract.CallOpts, arg0) -} - -// SlopeChanges is a free data retrieval call binding the contract method 0x71197484. -// -// Solidity: function slope_changes(uint256 arg0) view returns(int128) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) SlopeChanges(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "slope_changes", arg0) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// SlopeChanges is a free data retrieval call binding the contract method 0x71197484. -// -// Solidity: function slope_changes(uint256 arg0) view returns(int128) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) SlopeChanges(arg0 *big.Int) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.SlopeChanges(&_Nation3VestedTokenContract.CallOpts, arg0) -} - -// SlopeChanges is a free data retrieval call binding the contract method 0x71197484. -// -// Solidity: function slope_changes(uint256 arg0) view returns(int128) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) SlopeChanges(arg0 *big.Int) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.SlopeChanges(&_Nation3VestedTokenContract.CallOpts, arg0) -} - -// SmartWalletChecker is a free data retrieval call binding the contract method 0x7175d4f7. -// -// Solidity: function smart_wallet_checker() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) SmartWalletChecker(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "smart_wallet_checker") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// SmartWalletChecker is a free data retrieval call binding the contract method 0x7175d4f7. -// -// Solidity: function smart_wallet_checker() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) SmartWalletChecker() (common.Address, error) { - return _Nation3VestedTokenContract.Contract.SmartWalletChecker(&_Nation3VestedTokenContract.CallOpts) -} - -// SmartWalletChecker is a free data retrieval call binding the contract method 0x7175d4f7. -// -// Solidity: function smart_wallet_checker() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) SmartWalletChecker() (common.Address, error) { - return _Nation3VestedTokenContract.Contract.SmartWalletChecker(&_Nation3VestedTokenContract.CallOpts) -} - -// Supply is a free data retrieval call binding the contract method 0x047fc9aa. -// -// Solidity: function supply() view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) Supply(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "supply") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Supply is a free data retrieval call binding the contract method 0x047fc9aa. -// -// Solidity: function supply() view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) Supply() (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.Supply(&_Nation3VestedTokenContract.CallOpts) -} - -// Supply is a free data retrieval call binding the contract method 0x047fc9aa. -// -// Solidity: function supply() view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) Supply() (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.Supply(&_Nation3VestedTokenContract.CallOpts) -} - -// Symbol is a free data retrieval call binding the contract method 0x95d89b41. -// -// Solidity: function symbol() view returns(string) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) Symbol(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "symbol") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// Symbol is a free data retrieval call binding the contract method 0x95d89b41. -// -// Solidity: function symbol() view returns(string) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) Symbol() (string, error) { - return _Nation3VestedTokenContract.Contract.Symbol(&_Nation3VestedTokenContract.CallOpts) -} - -// Symbol is a free data retrieval call binding the contract method 0x95d89b41. -// -// Solidity: function symbol() view returns(string) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) Symbol() (string, error) { - return _Nation3VestedTokenContract.Contract.Symbol(&_Nation3VestedTokenContract.CallOpts) -} - -// Token is a free data retrieval call binding the contract method 0xfc0c546a. -// -// Solidity: function token() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) Token(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "token") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Token is a free data retrieval call binding the contract method 0xfc0c546a. -// -// Solidity: function token() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) Token() (common.Address, error) { - return _Nation3VestedTokenContract.Contract.Token(&_Nation3VestedTokenContract.CallOpts) -} - -// Token is a free data retrieval call binding the contract method 0xfc0c546a. -// -// Solidity: function token() view returns(address) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) Token() (common.Address, error) { - return _Nation3VestedTokenContract.Contract.Token(&_Nation3VestedTokenContract.CallOpts) -} - -// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. -// -// Solidity: function totalSupply() view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "totalSupply") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. -// -// Solidity: function totalSupply() view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) TotalSupply() (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.TotalSupply(&_Nation3VestedTokenContract.CallOpts) -} - -// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. -// -// Solidity: function totalSupply() view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) TotalSupply() (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.TotalSupply(&_Nation3VestedTokenContract.CallOpts) -} - -// TotalSupply0 is a free data retrieval call binding the contract method 0xbd85b039. -// -// Solidity: function totalSupply(uint256 t) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) TotalSupply0(opts *bind.CallOpts, t *big.Int) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "totalSupply0", t) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// TotalSupply0 is a free data retrieval call binding the contract method 0xbd85b039. -// -// Solidity: function totalSupply(uint256 t) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) TotalSupply0(t *big.Int) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.TotalSupply0(&_Nation3VestedTokenContract.CallOpts, t) -} - -// TotalSupply0 is a free data retrieval call binding the contract method 0xbd85b039. -// -// Solidity: function totalSupply(uint256 t) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) TotalSupply0(t *big.Int) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.TotalSupply0(&_Nation3VestedTokenContract.CallOpts, t) -} - -// TotalSupplyAt is a free data retrieval call binding the contract method 0x981b24d0. -// -// Solidity: function totalSupplyAt(uint256 _block) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) TotalSupplyAt(opts *bind.CallOpts, _block *big.Int) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "totalSupplyAt", _block) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// TotalSupplyAt is a free data retrieval call binding the contract method 0x981b24d0. -// -// Solidity: function totalSupplyAt(uint256 _block) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) TotalSupplyAt(_block *big.Int) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.TotalSupplyAt(&_Nation3VestedTokenContract.CallOpts, _block) -} - -// TotalSupplyAt is a free data retrieval call binding the contract method 0x981b24d0. -// -// Solidity: function totalSupplyAt(uint256 _block) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) TotalSupplyAt(_block *big.Int) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.TotalSupplyAt(&_Nation3VestedTokenContract.CallOpts, _block) -} - -// TransfersEnabled is a free data retrieval call binding the contract method 0xbef97c87. -// -// Solidity: function transfersEnabled() view returns(bool) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) TransfersEnabled(opts *bind.CallOpts) (bool, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "transfersEnabled") - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// TransfersEnabled is a free data retrieval call binding the contract method 0xbef97c87. -// -// Solidity: function transfersEnabled() view returns(bool) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) TransfersEnabled() (bool, error) { - return _Nation3VestedTokenContract.Contract.TransfersEnabled(&_Nation3VestedTokenContract.CallOpts) -} - -// TransfersEnabled is a free data retrieval call binding the contract method 0xbef97c87. -// -// Solidity: function transfersEnabled() view returns(bool) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) TransfersEnabled() (bool, error) { - return _Nation3VestedTokenContract.Contract.TransfersEnabled(&_Nation3VestedTokenContract.CallOpts) -} - -// UserPointEpoch is a free data retrieval call binding the contract method 0x010ae757. -// -// Solidity: function user_point_epoch(address arg0) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) UserPointEpoch(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "user_point_epoch", arg0) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// UserPointEpoch is a free data retrieval call binding the contract method 0x010ae757. -// -// Solidity: function user_point_epoch(address arg0) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) UserPointEpoch(arg0 common.Address) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.UserPointEpoch(&_Nation3VestedTokenContract.CallOpts, arg0) -} - -// UserPointEpoch is a free data retrieval call binding the contract method 0x010ae757. -// -// Solidity: function user_point_epoch(address arg0) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) UserPointEpoch(arg0 common.Address) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.UserPointEpoch(&_Nation3VestedTokenContract.CallOpts, arg0) -} - -// UserPointHistory is a free data retrieval call binding the contract method 0x28d09d47. -// -// Solidity: function user_point_history(address arg0, uint256 arg1) view returns(int128 bias, int128 slope, uint256 ts, uint256 blk) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) UserPointHistory(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) (struct { - Bias *big.Int - Slope *big.Int - Ts *big.Int - Blk *big.Int -}, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "user_point_history", arg0, arg1) - - outstruct := new(struct { - Bias *big.Int - Slope *big.Int - Ts *big.Int - Blk *big.Int - }) - if err != nil { - return *outstruct, err - } - - outstruct.Bias = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - outstruct.Slope = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - outstruct.Ts = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) - outstruct.Blk = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) - - return *outstruct, err - -} - -// UserPointHistory is a free data retrieval call binding the contract method 0x28d09d47. -// -// Solidity: function user_point_history(address arg0, uint256 arg1) view returns(int128 bias, int128 slope, uint256 ts, uint256 blk) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) UserPointHistory(arg0 common.Address, arg1 *big.Int) (struct { - Bias *big.Int - Slope *big.Int - Ts *big.Int - Blk *big.Int -}, error) { - return _Nation3VestedTokenContract.Contract.UserPointHistory(&_Nation3VestedTokenContract.CallOpts, arg0, arg1) -} - -// UserPointHistory is a free data retrieval call binding the contract method 0x28d09d47. -// -// Solidity: function user_point_history(address arg0, uint256 arg1) view returns(int128 bias, int128 slope, uint256 ts, uint256 blk) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) UserPointHistory(arg0 common.Address, arg1 *big.Int) (struct { - Bias *big.Int - Slope *big.Int - Ts *big.Int - Blk *big.Int -}, error) { - return _Nation3VestedTokenContract.Contract.UserPointHistory(&_Nation3VestedTokenContract.CallOpts, arg0, arg1) -} - -// UserPointHistoryTs is a free data retrieval call binding the contract method 0xda020a18. -// -// Solidity: function user_point_history__ts(address _addr, uint256 _idx) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) UserPointHistoryTs(opts *bind.CallOpts, _addr common.Address, _idx *big.Int) (*big.Int, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "user_point_history__ts", _addr, _idx) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// UserPointHistoryTs is a free data retrieval call binding the contract method 0xda020a18. -// -// Solidity: function user_point_history__ts(address _addr, uint256 _idx) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) UserPointHistoryTs(_addr common.Address, _idx *big.Int) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.UserPointHistoryTs(&_Nation3VestedTokenContract.CallOpts, _addr, _idx) -} - -// UserPointHistoryTs is a free data retrieval call binding the contract method 0xda020a18. -// -// Solidity: function user_point_history__ts(address _addr, uint256 _idx) view returns(uint256) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) UserPointHistoryTs(_addr common.Address, _idx *big.Int) (*big.Int, error) { - return _Nation3VestedTokenContract.Contract.UserPointHistoryTs(&_Nation3VestedTokenContract.CallOpts, _addr, _idx) -} - -// Version is a free data retrieval call binding the contract method 0x54fd4d50. -// -// Solidity: function version() view returns(string) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCaller) Version(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _Nation3VestedTokenContract.contract.Call(opts, &out, "version") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// Version is a free data retrieval call binding the contract method 0x54fd4d50. -// -// Solidity: function version() view returns(string) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) Version() (string, error) { - return _Nation3VestedTokenContract.Contract.Version(&_Nation3VestedTokenContract.CallOpts) -} - -// Version is a free data retrieval call binding the contract method 0x54fd4d50. -// -// Solidity: function version() view returns(string) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractCallerSession) Version() (string, error) { - return _Nation3VestedTokenContract.Contract.Version(&_Nation3VestedTokenContract.CallOpts) -} - -// ApplySmartWalletChecker is a paid mutator transaction binding the contract method 0x8e5b490f. -// -// Solidity: function apply_smart_wallet_checker() returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactor) ApplySmartWalletChecker(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Nation3VestedTokenContract.contract.Transact(opts, "apply_smart_wallet_checker") -} - -// ApplySmartWalletChecker is a paid mutator transaction binding the contract method 0x8e5b490f. -// -// Solidity: function apply_smart_wallet_checker() returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) ApplySmartWalletChecker() (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.ApplySmartWalletChecker(&_Nation3VestedTokenContract.TransactOpts) -} - -// ApplySmartWalletChecker is a paid mutator transaction binding the contract method 0x8e5b490f. -// -// Solidity: function apply_smart_wallet_checker() returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorSession) ApplySmartWalletChecker() (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.ApplySmartWalletChecker(&_Nation3VestedTokenContract.TransactOpts) -} - -// ApplyTransferOwnership is a paid mutator transaction binding the contract method 0x6a1c05ae. -// -// Solidity: function apply_transfer_ownership() returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactor) ApplyTransferOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Nation3VestedTokenContract.contract.Transact(opts, "apply_transfer_ownership") -} - -// ApplyTransferOwnership is a paid mutator transaction binding the contract method 0x6a1c05ae. -// -// Solidity: function apply_transfer_ownership() returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) ApplyTransferOwnership() (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.ApplyTransferOwnership(&_Nation3VestedTokenContract.TransactOpts) -} - -// ApplyTransferOwnership is a paid mutator transaction binding the contract method 0x6a1c05ae. -// -// Solidity: function apply_transfer_ownership() returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorSession) ApplyTransferOwnership() (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.ApplyTransferOwnership(&_Nation3VestedTokenContract.TransactOpts) -} - -// ChangeController is a paid mutator transaction binding the contract method 0x3cebb823. -// -// Solidity: function changeController(address _newController) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactor) ChangeController(opts *bind.TransactOpts, _newController common.Address) (*types.Transaction, error) { - return _Nation3VestedTokenContract.contract.Transact(opts, "changeController", _newController) -} - -// ChangeController is a paid mutator transaction binding the contract method 0x3cebb823. -// -// Solidity: function changeController(address _newController) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) ChangeController(_newController common.Address) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.ChangeController(&_Nation3VestedTokenContract.TransactOpts, _newController) -} - -// ChangeController is a paid mutator transaction binding the contract method 0x3cebb823. -// -// Solidity: function changeController(address _newController) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorSession) ChangeController(_newController common.Address) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.ChangeController(&_Nation3VestedTokenContract.TransactOpts, _newController) -} - -// Checkpoint is a paid mutator transaction binding the contract method 0xc2c4c5c1. -// -// Solidity: function checkpoint() returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactor) Checkpoint(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Nation3VestedTokenContract.contract.Transact(opts, "checkpoint") -} - -// Checkpoint is a paid mutator transaction binding the contract method 0xc2c4c5c1. -// -// Solidity: function checkpoint() returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) Checkpoint() (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.Checkpoint(&_Nation3VestedTokenContract.TransactOpts) -} - -// Checkpoint is a paid mutator transaction binding the contract method 0xc2c4c5c1. -// -// Solidity: function checkpoint() returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorSession) Checkpoint() (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.Checkpoint(&_Nation3VestedTokenContract.TransactOpts) -} - -// CommitSmartWalletChecker is a paid mutator transaction binding the contract method 0x57f901e2. -// -// Solidity: function commit_smart_wallet_checker(address addr) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactor) CommitSmartWalletChecker(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { - return _Nation3VestedTokenContract.contract.Transact(opts, "commit_smart_wallet_checker", addr) -} - -// CommitSmartWalletChecker is a paid mutator transaction binding the contract method 0x57f901e2. -// -// Solidity: function commit_smart_wallet_checker(address addr) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) CommitSmartWalletChecker(addr common.Address) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.CommitSmartWalletChecker(&_Nation3VestedTokenContract.TransactOpts, addr) -} - -// CommitSmartWalletChecker is a paid mutator transaction binding the contract method 0x57f901e2. -// -// Solidity: function commit_smart_wallet_checker(address addr) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorSession) CommitSmartWalletChecker(addr common.Address) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.CommitSmartWalletChecker(&_Nation3VestedTokenContract.TransactOpts, addr) -} - -// CommitTransferOwnership is a paid mutator transaction binding the contract method 0x6b441a40. -// -// Solidity: function commit_transfer_ownership(address addr) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactor) CommitTransferOwnership(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { - return _Nation3VestedTokenContract.contract.Transact(opts, "commit_transfer_ownership", addr) -} - -// CommitTransferOwnership is a paid mutator transaction binding the contract method 0x6b441a40. -// -// Solidity: function commit_transfer_ownership(address addr) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) CommitTransferOwnership(addr common.Address) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.CommitTransferOwnership(&_Nation3VestedTokenContract.TransactOpts, addr) -} - -// CommitTransferOwnership is a paid mutator transaction binding the contract method 0x6b441a40. -// -// Solidity: function commit_transfer_ownership(address addr) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorSession) CommitTransferOwnership(addr common.Address) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.CommitTransferOwnership(&_Nation3VestedTokenContract.TransactOpts, addr) -} - -// CreateLock is a paid mutator transaction binding the contract method 0x65fc3873. -// -// Solidity: function create_lock(uint256 _value, uint256 _unlock_time) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactor) CreateLock(opts *bind.TransactOpts, _value *big.Int, _unlock_time *big.Int) (*types.Transaction, error) { - return _Nation3VestedTokenContract.contract.Transact(opts, "create_lock", _value, _unlock_time) -} - -// CreateLock is a paid mutator transaction binding the contract method 0x65fc3873. -// -// Solidity: function create_lock(uint256 _value, uint256 _unlock_time) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) CreateLock(_value *big.Int, _unlock_time *big.Int) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.CreateLock(&_Nation3VestedTokenContract.TransactOpts, _value, _unlock_time) -} - -// CreateLock is a paid mutator transaction binding the contract method 0x65fc3873. -// -// Solidity: function create_lock(uint256 _value, uint256 _unlock_time) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorSession) CreateLock(_value *big.Int, _unlock_time *big.Int) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.CreateLock(&_Nation3VestedTokenContract.TransactOpts, _value, _unlock_time) -} - -// DepositFor is a paid mutator transaction binding the contract method 0x3a46273e. -// -// Solidity: function deposit_for(address _addr, uint256 _value) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactor) DepositFor(opts *bind.TransactOpts, _addr common.Address, _value *big.Int) (*types.Transaction, error) { - return _Nation3VestedTokenContract.contract.Transact(opts, "deposit_for", _addr, _value) -} - -// DepositFor is a paid mutator transaction binding the contract method 0x3a46273e. -// -// Solidity: function deposit_for(address _addr, uint256 _value) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) DepositFor(_addr common.Address, _value *big.Int) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.DepositFor(&_Nation3VestedTokenContract.TransactOpts, _addr, _value) -} - -// DepositFor is a paid mutator transaction binding the contract method 0x3a46273e. -// -// Solidity: function deposit_for(address _addr, uint256 _value) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorSession) DepositFor(_addr common.Address, _value *big.Int) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.DepositFor(&_Nation3VestedTokenContract.TransactOpts, _addr, _value) -} - -// IncreaseAmount is a paid mutator transaction binding the contract method 0x4957677c. -// -// Solidity: function increase_amount(uint256 _value) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactor) IncreaseAmount(opts *bind.TransactOpts, _value *big.Int) (*types.Transaction, error) { - return _Nation3VestedTokenContract.contract.Transact(opts, "increase_amount", _value) -} - -// IncreaseAmount is a paid mutator transaction binding the contract method 0x4957677c. -// -// Solidity: function increase_amount(uint256 _value) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) IncreaseAmount(_value *big.Int) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.IncreaseAmount(&_Nation3VestedTokenContract.TransactOpts, _value) -} - -// IncreaseAmount is a paid mutator transaction binding the contract method 0x4957677c. -// -// Solidity: function increase_amount(uint256 _value) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorSession) IncreaseAmount(_value *big.Int) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.IncreaseAmount(&_Nation3VestedTokenContract.TransactOpts, _value) -} - -// IncreaseUnlockTime is a paid mutator transaction binding the contract method 0xeff7a612. -// -// Solidity: function increase_unlock_time(uint256 _unlock_time) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactor) IncreaseUnlockTime(opts *bind.TransactOpts, _unlock_time *big.Int) (*types.Transaction, error) { - return _Nation3VestedTokenContract.contract.Transact(opts, "increase_unlock_time", _unlock_time) -} - -// IncreaseUnlockTime is a paid mutator transaction binding the contract method 0xeff7a612. -// -// Solidity: function increase_unlock_time(uint256 _unlock_time) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) IncreaseUnlockTime(_unlock_time *big.Int) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.IncreaseUnlockTime(&_Nation3VestedTokenContract.TransactOpts, _unlock_time) -} - -// IncreaseUnlockTime is a paid mutator transaction binding the contract method 0xeff7a612. -// -// Solidity: function increase_unlock_time(uint256 _unlock_time) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorSession) IncreaseUnlockTime(_unlock_time *big.Int) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.IncreaseUnlockTime(&_Nation3VestedTokenContract.TransactOpts, _unlock_time) -} - -// SetDepositsLocked is a paid mutator transaction binding the contract method 0x4e782813. -// -// Solidity: function set_depositsLocked(bool new_status) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactor) SetDepositsLocked(opts *bind.TransactOpts, new_status bool) (*types.Transaction, error) { - return _Nation3VestedTokenContract.contract.Transact(opts, "set_depositsLocked", new_status) -} - -// SetDepositsLocked is a paid mutator transaction binding the contract method 0x4e782813. -// -// Solidity: function set_depositsLocked(bool new_status) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) SetDepositsLocked(new_status bool) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.SetDepositsLocked(&_Nation3VestedTokenContract.TransactOpts, new_status) -} - -// SetDepositsLocked is a paid mutator transaction binding the contract method 0x4e782813. -// -// Solidity: function set_depositsLocked(bool new_status) returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorSession) SetDepositsLocked(new_status bool) (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.SetDepositsLocked(&_Nation3VestedTokenContract.TransactOpts, new_status) -} - -// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. -// -// Solidity: function withdraw() returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactor) Withdraw(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Nation3VestedTokenContract.contract.Transact(opts, "withdraw") -} - -// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. -// -// Solidity: function withdraw() returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractSession) Withdraw() (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.Withdraw(&_Nation3VestedTokenContract.TransactOpts) -} - -// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. -// -// Solidity: function withdraw() returns() -func (_Nation3VestedTokenContract *Nation3VestedTokenContractTransactorSession) Withdraw() (*types.Transaction, error) { - return _Nation3VestedTokenContract.Contract.Withdraw(&_Nation3VestedTokenContract.TransactOpts) -} - -// Nation3VestedTokenContractApplyOwnershipIterator is returned from FilterApplyOwnership and is used to iterate over the raw logs and unpacked data for ApplyOwnership events raised by the Nation3VestedTokenContract contract. -type Nation3VestedTokenContractApplyOwnershipIterator struct { - Event *Nation3VestedTokenContractApplyOwnership // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *Nation3VestedTokenContractApplyOwnershipIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(Nation3VestedTokenContractApplyOwnership) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(Nation3VestedTokenContractApplyOwnership) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *Nation3VestedTokenContractApplyOwnershipIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *Nation3VestedTokenContractApplyOwnershipIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// Nation3VestedTokenContractApplyOwnership represents a ApplyOwnership event raised by the Nation3VestedTokenContract contract. -type Nation3VestedTokenContractApplyOwnership struct { - Admin common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterApplyOwnership is a free log retrieval operation binding the contract event 0xebee2d5739011062cb4f14113f3b36bf0ffe3da5c0568f64189d1012a1189105. -// -// Solidity: event ApplyOwnership(address admin) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) FilterApplyOwnership(opts *bind.FilterOpts) (*Nation3VestedTokenContractApplyOwnershipIterator, error) { - - logs, sub, err := _Nation3VestedTokenContract.contract.FilterLogs(opts, "ApplyOwnership") - if err != nil { - return nil, err - } - return &Nation3VestedTokenContractApplyOwnershipIterator{contract: _Nation3VestedTokenContract.contract, event: "ApplyOwnership", logs: logs, sub: sub}, nil -} - -// WatchApplyOwnership is a free log subscription operation binding the contract event 0xebee2d5739011062cb4f14113f3b36bf0ffe3da5c0568f64189d1012a1189105. -// -// Solidity: event ApplyOwnership(address admin) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) WatchApplyOwnership(opts *bind.WatchOpts, sink chan<- *Nation3VestedTokenContractApplyOwnership) (event.Subscription, error) { - - logs, sub, err := _Nation3VestedTokenContract.contract.WatchLogs(opts, "ApplyOwnership") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(Nation3VestedTokenContractApplyOwnership) - if err := _Nation3VestedTokenContract.contract.UnpackLog(event, "ApplyOwnership", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseApplyOwnership is a log parse operation binding the contract event 0xebee2d5739011062cb4f14113f3b36bf0ffe3da5c0568f64189d1012a1189105. -// -// Solidity: event ApplyOwnership(address admin) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) ParseApplyOwnership(log types.Log) (*Nation3VestedTokenContractApplyOwnership, error) { - event := new(Nation3VestedTokenContractApplyOwnership) - if err := _Nation3VestedTokenContract.contract.UnpackLog(event, "ApplyOwnership", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// Nation3VestedTokenContractCommitOwnershipIterator is returned from FilterCommitOwnership and is used to iterate over the raw logs and unpacked data for CommitOwnership events raised by the Nation3VestedTokenContract contract. -type Nation3VestedTokenContractCommitOwnershipIterator struct { - Event *Nation3VestedTokenContractCommitOwnership // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *Nation3VestedTokenContractCommitOwnershipIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(Nation3VestedTokenContractCommitOwnership) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(Nation3VestedTokenContractCommitOwnership) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *Nation3VestedTokenContractCommitOwnershipIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *Nation3VestedTokenContractCommitOwnershipIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// Nation3VestedTokenContractCommitOwnership represents a CommitOwnership event raised by the Nation3VestedTokenContract contract. -type Nation3VestedTokenContractCommitOwnership struct { - Admin common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterCommitOwnership is a free log retrieval operation binding the contract event 0x2f56810a6bf40af059b96d3aea4db54081f378029a518390491093a7b67032e9. -// -// Solidity: event CommitOwnership(address admin) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) FilterCommitOwnership(opts *bind.FilterOpts) (*Nation3VestedTokenContractCommitOwnershipIterator, error) { - - logs, sub, err := _Nation3VestedTokenContract.contract.FilterLogs(opts, "CommitOwnership") - if err != nil { - return nil, err - } - return &Nation3VestedTokenContractCommitOwnershipIterator{contract: _Nation3VestedTokenContract.contract, event: "CommitOwnership", logs: logs, sub: sub}, nil -} - -// WatchCommitOwnership is a free log subscription operation binding the contract event 0x2f56810a6bf40af059b96d3aea4db54081f378029a518390491093a7b67032e9. -// -// Solidity: event CommitOwnership(address admin) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) WatchCommitOwnership(opts *bind.WatchOpts, sink chan<- *Nation3VestedTokenContractCommitOwnership) (event.Subscription, error) { - - logs, sub, err := _Nation3VestedTokenContract.contract.WatchLogs(opts, "CommitOwnership") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(Nation3VestedTokenContractCommitOwnership) - if err := _Nation3VestedTokenContract.contract.UnpackLog(event, "CommitOwnership", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseCommitOwnership is a log parse operation binding the contract event 0x2f56810a6bf40af059b96d3aea4db54081f378029a518390491093a7b67032e9. -// -// Solidity: event CommitOwnership(address admin) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) ParseCommitOwnership(log types.Log) (*Nation3VestedTokenContractCommitOwnership, error) { - event := new(Nation3VestedTokenContractCommitOwnership) - if err := _Nation3VestedTokenContract.contract.UnpackLog(event, "CommitOwnership", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// Nation3VestedTokenContractDepositIterator is returned from FilterDeposit and is used to iterate over the raw logs and unpacked data for Deposit events raised by the Nation3VestedTokenContract contract. -type Nation3VestedTokenContractDepositIterator struct { - Event *Nation3VestedTokenContractDeposit // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *Nation3VestedTokenContractDepositIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(Nation3VestedTokenContractDeposit) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(Nation3VestedTokenContractDeposit) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *Nation3VestedTokenContractDepositIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *Nation3VestedTokenContractDepositIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// Nation3VestedTokenContractDeposit represents a Deposit event raised by the Nation3VestedTokenContract contract. -type Nation3VestedTokenContractDeposit struct { - Provider common.Address - Value *big.Int - Locktime *big.Int - Arg3 *big.Int - Ts *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterDeposit is a free log retrieval operation binding the contract event 0x4566dfc29f6f11d13a418c26a02bef7c28bae749d4de47e4e6a7cddea6730d59. -// -// Solidity: event Deposit(address indexed provider, uint256 value, uint256 indexed locktime, int128 type, uint256 ts) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) FilterDeposit(opts *bind.FilterOpts, provider []common.Address, locktime []*big.Int) (*Nation3VestedTokenContractDepositIterator, error) { - - var providerRule []interface{} - for _, providerItem := range provider { - providerRule = append(providerRule, providerItem) - } - - var locktimeRule []interface{} - for _, locktimeItem := range locktime { - locktimeRule = append(locktimeRule, locktimeItem) - } - - logs, sub, err := _Nation3VestedTokenContract.contract.FilterLogs(opts, "Deposit", providerRule, locktimeRule) - if err != nil { - return nil, err - } - return &Nation3VestedTokenContractDepositIterator{contract: _Nation3VestedTokenContract.contract, event: "Deposit", logs: logs, sub: sub}, nil -} - -// WatchDeposit is a free log subscription operation binding the contract event 0x4566dfc29f6f11d13a418c26a02bef7c28bae749d4de47e4e6a7cddea6730d59. -// -// Solidity: event Deposit(address indexed provider, uint256 value, uint256 indexed locktime, int128 type, uint256 ts) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) WatchDeposit(opts *bind.WatchOpts, sink chan<- *Nation3VestedTokenContractDeposit, provider []common.Address, locktime []*big.Int) (event.Subscription, error) { - - var providerRule []interface{} - for _, providerItem := range provider { - providerRule = append(providerRule, providerItem) - } - - var locktimeRule []interface{} - for _, locktimeItem := range locktime { - locktimeRule = append(locktimeRule, locktimeItem) - } - - logs, sub, err := _Nation3VestedTokenContract.contract.WatchLogs(opts, "Deposit", providerRule, locktimeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(Nation3VestedTokenContractDeposit) - if err := _Nation3VestedTokenContract.contract.UnpackLog(event, "Deposit", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseDeposit is a log parse operation binding the contract event 0x4566dfc29f6f11d13a418c26a02bef7c28bae749d4de47e4e6a7cddea6730d59. -// -// Solidity: event Deposit(address indexed provider, uint256 value, uint256 indexed locktime, int128 type, uint256 ts) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) ParseDeposit(log types.Log) (*Nation3VestedTokenContractDeposit, error) { - event := new(Nation3VestedTokenContractDeposit) - if err := _Nation3VestedTokenContract.contract.UnpackLog(event, "Deposit", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// Nation3VestedTokenContractDepositsLockedChangeIterator is returned from FilterDepositsLockedChange and is used to iterate over the raw logs and unpacked data for DepositsLockedChange events raised by the Nation3VestedTokenContract contract. -type Nation3VestedTokenContractDepositsLockedChangeIterator struct { - Event *Nation3VestedTokenContractDepositsLockedChange // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *Nation3VestedTokenContractDepositsLockedChangeIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(Nation3VestedTokenContractDepositsLockedChange) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(Nation3VestedTokenContractDepositsLockedChange) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *Nation3VestedTokenContractDepositsLockedChangeIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *Nation3VestedTokenContractDepositsLockedChangeIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// Nation3VestedTokenContractDepositsLockedChange represents a DepositsLockedChange event raised by the Nation3VestedTokenContract contract. -type Nation3VestedTokenContractDepositsLockedChange struct { - Status bool - Raw types.Log // Blockchain specific contextual infos -} - -// FilterDepositsLockedChange is a free log retrieval operation binding the contract event 0x3a6f72b4ed02517aec1d580529f912e860631ecb6fec4712d400294932aaffba. -// -// Solidity: event DepositsLockedChange(bool status) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) FilterDepositsLockedChange(opts *bind.FilterOpts) (*Nation3VestedTokenContractDepositsLockedChangeIterator, error) { - - logs, sub, err := _Nation3VestedTokenContract.contract.FilterLogs(opts, "DepositsLockedChange") - if err != nil { - return nil, err - } - return &Nation3VestedTokenContractDepositsLockedChangeIterator{contract: _Nation3VestedTokenContract.contract, event: "DepositsLockedChange", logs: logs, sub: sub}, nil -} - -// WatchDepositsLockedChange is a free log subscription operation binding the contract event 0x3a6f72b4ed02517aec1d580529f912e860631ecb6fec4712d400294932aaffba. -// -// Solidity: event DepositsLockedChange(bool status) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) WatchDepositsLockedChange(opts *bind.WatchOpts, sink chan<- *Nation3VestedTokenContractDepositsLockedChange) (event.Subscription, error) { - - logs, sub, err := _Nation3VestedTokenContract.contract.WatchLogs(opts, "DepositsLockedChange") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(Nation3VestedTokenContractDepositsLockedChange) - if err := _Nation3VestedTokenContract.contract.UnpackLog(event, "DepositsLockedChange", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseDepositsLockedChange is a log parse operation binding the contract event 0x3a6f72b4ed02517aec1d580529f912e860631ecb6fec4712d400294932aaffba. -// -// Solidity: event DepositsLockedChange(bool status) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) ParseDepositsLockedChange(log types.Log) (*Nation3VestedTokenContractDepositsLockedChange, error) { - event := new(Nation3VestedTokenContractDepositsLockedChange) - if err := _Nation3VestedTokenContract.contract.UnpackLog(event, "DepositsLockedChange", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// Nation3VestedTokenContractSupplyIterator is returned from FilterSupply and is used to iterate over the raw logs and unpacked data for Supply events raised by the Nation3VestedTokenContract contract. -type Nation3VestedTokenContractSupplyIterator struct { - Event *Nation3VestedTokenContractSupply // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *Nation3VestedTokenContractSupplyIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(Nation3VestedTokenContractSupply) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(Nation3VestedTokenContractSupply) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *Nation3VestedTokenContractSupplyIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *Nation3VestedTokenContractSupplyIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// Nation3VestedTokenContractSupply represents a Supply event raised by the Nation3VestedTokenContract contract. -type Nation3VestedTokenContractSupply struct { - PrevSupply *big.Int - Supply *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSupply is a free log retrieval operation binding the contract event 0x5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c. -// -// Solidity: event Supply(uint256 prevSupply, uint256 supply) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) FilterSupply(opts *bind.FilterOpts) (*Nation3VestedTokenContractSupplyIterator, error) { - - logs, sub, err := _Nation3VestedTokenContract.contract.FilterLogs(opts, "Supply") - if err != nil { - return nil, err - } - return &Nation3VestedTokenContractSupplyIterator{contract: _Nation3VestedTokenContract.contract, event: "Supply", logs: logs, sub: sub}, nil -} - -// WatchSupply is a free log subscription operation binding the contract event 0x5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c. -// -// Solidity: event Supply(uint256 prevSupply, uint256 supply) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) WatchSupply(opts *bind.WatchOpts, sink chan<- *Nation3VestedTokenContractSupply) (event.Subscription, error) { - - logs, sub, err := _Nation3VestedTokenContract.contract.WatchLogs(opts, "Supply") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(Nation3VestedTokenContractSupply) - if err := _Nation3VestedTokenContract.contract.UnpackLog(event, "Supply", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSupply is a log parse operation binding the contract event 0x5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c. -// -// Solidity: event Supply(uint256 prevSupply, uint256 supply) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) ParseSupply(log types.Log) (*Nation3VestedTokenContractSupply, error) { - event := new(Nation3VestedTokenContractSupply) - if err := _Nation3VestedTokenContract.contract.UnpackLog(event, "Supply", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// Nation3VestedTokenContractWithdrawIterator is returned from FilterWithdraw and is used to iterate over the raw logs and unpacked data for Withdraw events raised by the Nation3VestedTokenContract contract. -type Nation3VestedTokenContractWithdrawIterator struct { - Event *Nation3VestedTokenContractWithdraw // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *Nation3VestedTokenContractWithdrawIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(Nation3VestedTokenContractWithdraw) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(Nation3VestedTokenContractWithdraw) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *Nation3VestedTokenContractWithdrawIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *Nation3VestedTokenContractWithdrawIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// Nation3VestedTokenContractWithdraw represents a Withdraw event raised by the Nation3VestedTokenContract contract. -type Nation3VestedTokenContractWithdraw struct { - Provider common.Address - Value *big.Int - Ts *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterWithdraw is a free log retrieval operation binding the contract event 0xf279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568. -// -// Solidity: event Withdraw(address indexed provider, uint256 value, uint256 ts) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) FilterWithdraw(opts *bind.FilterOpts, provider []common.Address) (*Nation3VestedTokenContractWithdrawIterator, error) { - - var providerRule []interface{} - for _, providerItem := range provider { - providerRule = append(providerRule, providerItem) - } - - logs, sub, err := _Nation3VestedTokenContract.contract.FilterLogs(opts, "Withdraw", providerRule) - if err != nil { - return nil, err - } - return &Nation3VestedTokenContractWithdrawIterator{contract: _Nation3VestedTokenContract.contract, event: "Withdraw", logs: logs, sub: sub}, nil -} - -// WatchWithdraw is a free log subscription operation binding the contract event 0xf279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568. -// -// Solidity: event Withdraw(address indexed provider, uint256 value, uint256 ts) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) WatchWithdraw(opts *bind.WatchOpts, sink chan<- *Nation3VestedTokenContractWithdraw, provider []common.Address) (event.Subscription, error) { - - var providerRule []interface{} - for _, providerItem := range provider { - providerRule = append(providerRule, providerItem) - } - - logs, sub, err := _Nation3VestedTokenContract.contract.WatchLogs(opts, "Withdraw", providerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(Nation3VestedTokenContractWithdraw) - if err := _Nation3VestedTokenContract.contract.UnpackLog(event, "Withdraw", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseWithdraw is a log parse operation binding the contract event 0xf279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568. -// -// Solidity: event Withdraw(address indexed provider, uint256 value, uint256 ts) -func (_Nation3VestedTokenContract *Nation3VestedTokenContractFilterer) ParseWithdraw(log types.Log) (*Nation3VestedTokenContractWithdraw, error) { - event := new(Nation3VestedTokenContractWithdraw) - if err := _Nation3VestedTokenContract.contract.UnpackLog(event, "Withdraw", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/contracts/poap/poap.abi b/contracts/poap/poap.abi deleted file mode 100644 index 67254d9b..00000000 --- a/contracts/poap/poap.abi +++ /dev/null @@ -1,960 +0,0 @@ -[ - { - "constant": true, - "inputs": [ - { - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "eventId", - "type": "uint256" - } - ], - "name": "renounceEventMinter", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "name", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "tokenId", - "type": "uint256" - } - ], - "name": "getApproved", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "to", - "type": "address" - }, - { - "name": "tokenId", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "tokenId", - "type": "uint256" - } - ], - "name": "tokenEvent", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "eventId", - "type": "uint256" - }, - { - "name": "account", - "type": "address" - } - ], - "name": "removeEventMinter", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "newLastId", - "type": "uint256" - } - ], - "name": "setLastId", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "from", - "type": "address" - }, - { - "name": "to", - "type": "address" - }, - { - "name": "tokenId", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "account", - "type": "address" - } - ], - "name": "isAdmin", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "eventId", - "type": "uint256" - }, - { - "name": "to", - "type": "address[]" - } - ], - "name": "mintEventToManyUsers", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "eventId", - "type": "uint256" - }, - { - "name": "account", - "type": "address" - } - ], - "name": "isEventMinter", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "owner", - "type": "address" - }, - { - "name": "index", - "type": "uint256" - } - ], - "name": "tokenOfOwnerByIndex", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "unpause", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "from", - "type": "address" - }, - { - "name": "to", - "type": "address" - }, - { - "name": "tokenId", - "type": "uint256" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "tokenId", - "type": "uint256" - } - ], - "name": "burn", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "freezeDuration", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "index", - "type": "uint256" - } - ], - "name": "tokenByIndex", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "baseURI", - "type": "string" - } - ], - "name": "setBaseURI", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "paused", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ownerOf", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "tokenId", - "type": "uint256" - } - ], - "name": "unfreeze", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "owner", - "type": "address" - }, - { - "name": "index", - "type": "uint256" - } - ], - "name": "tokenDetailsOfOwnerByIndex", - "outputs": [ - { - "name": "tokenId", - "type": "uint256" - }, - { - "name": "eventId", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "time", - "type": "uint256" - } - ], - "name": "setFreezeDuration", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "account", - "type": "address" - } - ], - "name": "addAdmin", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "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": false, - "inputs": [], - "name": "renounceAdmin", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "__name", - "type": "string" - }, - { - "name": "__symbol", - "type": "string" - }, - { - "name": "__baseURI", - "type": "string" - }, - { - "name": "admins", - "type": "address[]" - } - ], - "name": "initialize", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "tokenId", - "type": "uint256" - } - ], - "name": "getFreezeTime", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "symbol", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "eventId", - "type": "uint256" - }, - { - "name": "account", - "type": "address" - } - ], - "name": "addEventMinter", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "tokenId", - "type": "uint256" - } - ], - "name": "isFrozen", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "eventId", - "type": "uint256" - }, - { - "name": "to", - "type": "address" - } - ], - "name": "mintToken", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "to", - "type": "address" - }, - { - "name": "approved", - "type": "bool" - } - ], - "name": "setApprovalForAll", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "from", - "type": "address" - }, - { - "name": "to", - "type": "address" - }, - { - "name": "tokenId", - "type": "uint256" - }, - { - "name": "_data", - "type": "bytes" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "lastId", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "sender", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "tokenId", - "type": "uint256" - } - ], - "name": "tokenURI", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "tokenId", - "type": "uint256" - } - ], - "name": "freeze", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "owner", - "type": "address" - }, - { - "name": "operator", - "type": "address" - } - ], - "name": "isApprovedForAll", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "eventIds", - "type": "uint256[]" - }, - { - "name": "to", - "type": "address" - } - ], - "name": "mintUserToManyEvents", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "eventId", - "type": "uint256" - }, - { - "indexed": false, - "name": "tokenId", - "type": "uint256" - } - ], - "name": "EventToken", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "id", - "type": "uint256" - } - ], - "name": "Frozen", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "id", - "type": "uint256" - } - ], - "name": "Unfrozen", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "account", - "type": "address" - } - ], - "name": "AdminAdded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "account", - "type": "address" - } - ], - "name": "AdminRemoved", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "eventId", - "type": "uint256" - }, - { - "indexed": true, - "name": "account", - "type": "address" - } - ], - "name": "EventMinterAdded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "eventId", - "type": "uint256" - }, - { - "indexed": true, - "name": "account", - "type": "address" - } - ], - "name": "EventMinterRemoved", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "from", - "type": "address" - }, - { - "indexed": true, - "name": "to", - "type": "address" - }, - { - "indexed": true, - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "name": "approved", - "type": "address" - }, - { - "indexed": true, - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "name": "operator", - "type": "address" - }, - { - "indexed": false, - "name": "approved", - "type": "bool" - } - ], - "name": "ApprovalForAll", - "type": "event" - } -] \ No newline at end of file diff --git a/contracts/poap/poap.go b/contracts/poap/poap.go deleted file mode 100644 index 48468034..00000000 --- a/contracts/poap/poap.go +++ /dev/null @@ -1,3072 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package POAPContract - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// POAPContractMetaData contains all meta data concerning the POAPContract contract. -var POAPContractMetaData = &bind.MetaData{ - ABI: "[{\"constant\":true,\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"eventId\",\"type\":\"uint256\"}],\"name\":\"renounceEventMinter\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenEvent\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"eventId\",\"type\":\"uint256\"},{\"name\":\"account\",\"type\":\"address\"}],\"name\":\"removeEventMinter\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"newLastId\",\"type\":\"uint256\"}],\"name\":\"setLastId\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"account\",\"type\":\"address\"}],\"name\":\"isAdmin\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"eventId\",\"type\":\"uint256\"},{\"name\":\"to\",\"type\":\"address[]\"}],\"name\":\"mintEventToManyUsers\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"eventId\",\"type\":\"uint256\"},{\"name\":\"account\",\"type\":\"address\"}],\"name\":\"isEventMinter\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"},{\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"tokenOfOwnerByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"freezeDuration\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"tokenByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"baseURI\",\"type\":\"string\"}],\"name\":\"setBaseURI\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"unfreeze\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"},{\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"tokenDetailsOfOwnerByIndex\",\"outputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"},{\"name\":\"eventId\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"setFreezeDuration\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"account\",\"type\":\"address\"}],\"name\":\"addAdmin\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"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\":false,\"inputs\":[],\"name\":\"renounceAdmin\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"__name\",\"type\":\"string\"},{\"name\":\"__symbol\",\"type\":\"string\"},{\"name\":\"__baseURI\",\"type\":\"string\"},{\"name\":\"admins\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getFreezeTime\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"eventId\",\"type\":\"uint256\"},{\"name\":\"account\",\"type\":\"address\"}],\"name\":\"addEventMinter\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"isFrozen\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"eventId\",\"type\":\"uint256\"},{\"name\":\"to\",\"type\":\"address\"}],\"name\":\"mintToken\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"lastId\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"freeze\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"},{\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"eventIds\",\"type\":\"uint256[]\"},{\"name\":\"to\",\"type\":\"address\"}],\"name\":\"mintUserToManyEvents\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"eventId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"EventToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"Frozen\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"Unfrozen\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AdminAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AdminRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"eventId\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"account\",\"type\":\"address\"}],\"name\":\"EventMinterAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"eventId\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"account\",\"type\":\"address\"}],\"name\":\"EventMinterRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"approved\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"}]", -} - -// POAPContractABI is the input ABI used to generate the binding from. -// Deprecated: Use POAPContractMetaData.ABI instead. -var POAPContractABI = POAPContractMetaData.ABI - -// POAPContract is an auto generated Go binding around an Ethereum contract. -type POAPContract struct { - POAPContractCaller // Read-only binding to the contract - POAPContractTransactor // Write-only binding to the contract - POAPContractFilterer // Log filterer for contract events -} - -// POAPContractCaller is an auto generated read-only Go binding around an Ethereum contract. -type POAPContractCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// POAPContractTransactor is an auto generated write-only Go binding around an Ethereum contract. -type POAPContractTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// POAPContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type POAPContractFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// POAPContractSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type POAPContractSession struct { - Contract *POAPContract // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// POAPContractCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type POAPContractCallerSession struct { - Contract *POAPContractCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// POAPContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type POAPContractTransactorSession struct { - Contract *POAPContractTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// POAPContractRaw is an auto generated low-level Go binding around an Ethereum contract. -type POAPContractRaw struct { - Contract *POAPContract // Generic contract binding to access the raw methods on -} - -// POAPContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type POAPContractCallerRaw struct { - Contract *POAPContractCaller // Generic read-only contract binding to access the raw methods on -} - -// POAPContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type POAPContractTransactorRaw struct { - Contract *POAPContractTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewPOAPContract creates a new instance of POAPContract, bound to a specific deployed contract. -func NewPOAPContract(address common.Address, backend bind.ContractBackend) (*POAPContract, error) { - contract, err := bindPOAPContract(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &POAPContract{POAPContractCaller: POAPContractCaller{contract: contract}, POAPContractTransactor: POAPContractTransactor{contract: contract}, POAPContractFilterer: POAPContractFilterer{contract: contract}}, nil -} - -// NewPOAPContractCaller creates a new read-only instance of POAPContract, bound to a specific deployed contract. -func NewPOAPContractCaller(address common.Address, caller bind.ContractCaller) (*POAPContractCaller, error) { - contract, err := bindPOAPContract(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &POAPContractCaller{contract: contract}, nil -} - -// NewPOAPContractTransactor creates a new write-only instance of POAPContract, bound to a specific deployed contract. -func NewPOAPContractTransactor(address common.Address, transactor bind.ContractTransactor) (*POAPContractTransactor, error) { - contract, err := bindPOAPContract(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &POAPContractTransactor{contract: contract}, nil -} - -// NewPOAPContractFilterer creates a new log filterer instance of POAPContract, bound to a specific deployed contract. -func NewPOAPContractFilterer(address common.Address, filterer bind.ContractFilterer) (*POAPContractFilterer, error) { - contract, err := bindPOAPContract(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &POAPContractFilterer{contract: contract}, nil -} - -// bindPOAPContract binds a generic wrapper to an already deployed contract. -func bindPOAPContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := POAPContractMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_POAPContract *POAPContractRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _POAPContract.Contract.POAPContractCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_POAPContract *POAPContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _POAPContract.Contract.POAPContractTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_POAPContract *POAPContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _POAPContract.Contract.POAPContractTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_POAPContract *POAPContractCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _POAPContract.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_POAPContract *POAPContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _POAPContract.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_POAPContract *POAPContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _POAPContract.Contract.contract.Transact(opts, method, params...) -} - -// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. -// -// Solidity: function balanceOf(address owner) view returns(uint256) -func (_POAPContract *POAPContractCaller) BalanceOf(opts *bind.CallOpts, owner common.Address) (*big.Int, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "balanceOf", owner) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. -// -// Solidity: function balanceOf(address owner) view returns(uint256) -func (_POAPContract *POAPContractSession) BalanceOf(owner common.Address) (*big.Int, error) { - return _POAPContract.Contract.BalanceOf(&_POAPContract.CallOpts, owner) -} - -// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. -// -// Solidity: function balanceOf(address owner) view returns(uint256) -func (_POAPContract *POAPContractCallerSession) BalanceOf(owner common.Address) (*big.Int, error) { - return _POAPContract.Contract.BalanceOf(&_POAPContract.CallOpts, owner) -} - -// FreezeDuration is a free data retrieval call binding the contract method 0x440991bd. -// -// Solidity: function freezeDuration() view returns(uint256) -func (_POAPContract *POAPContractCaller) FreezeDuration(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "freezeDuration") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// FreezeDuration is a free data retrieval call binding the contract method 0x440991bd. -// -// Solidity: function freezeDuration() view returns(uint256) -func (_POAPContract *POAPContractSession) FreezeDuration() (*big.Int, error) { - return _POAPContract.Contract.FreezeDuration(&_POAPContract.CallOpts) -} - -// FreezeDuration is a free data retrieval call binding the contract method 0x440991bd. -// -// Solidity: function freezeDuration() view returns(uint256) -func (_POAPContract *POAPContractCallerSession) FreezeDuration() (*big.Int, error) { - return _POAPContract.Contract.FreezeDuration(&_POAPContract.CallOpts) -} - -// GetApproved is a free data retrieval call binding the contract method 0x081812fc. -// -// Solidity: function getApproved(uint256 tokenId) view returns(address) -func (_POAPContract *POAPContractCaller) GetApproved(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "getApproved", tokenId) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// GetApproved is a free data retrieval call binding the contract method 0x081812fc. -// -// Solidity: function getApproved(uint256 tokenId) view returns(address) -func (_POAPContract *POAPContractSession) GetApproved(tokenId *big.Int) (common.Address, error) { - return _POAPContract.Contract.GetApproved(&_POAPContract.CallOpts, tokenId) -} - -// GetApproved is a free data retrieval call binding the contract method 0x081812fc. -// -// Solidity: function getApproved(uint256 tokenId) view returns(address) -func (_POAPContract *POAPContractCallerSession) GetApproved(tokenId *big.Int) (common.Address, error) { - return _POAPContract.Contract.GetApproved(&_POAPContract.CallOpts, tokenId) -} - -// GetFreezeTime is a free data retrieval call binding the contract method 0x90fdd897. -// -// Solidity: function getFreezeTime(uint256 tokenId) view returns(uint256) -func (_POAPContract *POAPContractCaller) GetFreezeTime(opts *bind.CallOpts, tokenId *big.Int) (*big.Int, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "getFreezeTime", tokenId) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetFreezeTime is a free data retrieval call binding the contract method 0x90fdd897. -// -// Solidity: function getFreezeTime(uint256 tokenId) view returns(uint256) -func (_POAPContract *POAPContractSession) GetFreezeTime(tokenId *big.Int) (*big.Int, error) { - return _POAPContract.Contract.GetFreezeTime(&_POAPContract.CallOpts, tokenId) -} - -// GetFreezeTime is a free data retrieval call binding the contract method 0x90fdd897. -// -// Solidity: function getFreezeTime(uint256 tokenId) view returns(uint256) -func (_POAPContract *POAPContractCallerSession) GetFreezeTime(tokenId *big.Int) (*big.Int, error) { - return _POAPContract.Contract.GetFreezeTime(&_POAPContract.CallOpts, tokenId) -} - -// IsAdmin is a free data retrieval call binding the contract method 0x24d7806c. -// -// Solidity: function isAdmin(address account) view returns(bool) -func (_POAPContract *POAPContractCaller) IsAdmin(opts *bind.CallOpts, account common.Address) (bool, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "isAdmin", account) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsAdmin is a free data retrieval call binding the contract method 0x24d7806c. -// -// Solidity: function isAdmin(address account) view returns(bool) -func (_POAPContract *POAPContractSession) IsAdmin(account common.Address) (bool, error) { - return _POAPContract.Contract.IsAdmin(&_POAPContract.CallOpts, account) -} - -// IsAdmin is a free data retrieval call binding the contract method 0x24d7806c. -// -// Solidity: function isAdmin(address account) view returns(bool) -func (_POAPContract *POAPContractCallerSession) IsAdmin(account common.Address) (bool, error) { - return _POAPContract.Contract.IsAdmin(&_POAPContract.CallOpts, account) -} - -// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. -// -// Solidity: function isApprovedForAll(address owner, address operator) view returns(bool) -func (_POAPContract *POAPContractCaller) IsApprovedForAll(opts *bind.CallOpts, owner common.Address, operator common.Address) (bool, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "isApprovedForAll", owner, operator) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. -// -// Solidity: function isApprovedForAll(address owner, address operator) view returns(bool) -func (_POAPContract *POAPContractSession) IsApprovedForAll(owner common.Address, operator common.Address) (bool, error) { - return _POAPContract.Contract.IsApprovedForAll(&_POAPContract.CallOpts, owner, operator) -} - -// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. -// -// Solidity: function isApprovedForAll(address owner, address operator) view returns(bool) -func (_POAPContract *POAPContractCallerSession) IsApprovedForAll(owner common.Address, operator common.Address) (bool, error) { - return _POAPContract.Contract.IsApprovedForAll(&_POAPContract.CallOpts, owner, operator) -} - -// IsEventMinter is a free data retrieval call binding the contract method 0x28db38b4. -// -// Solidity: function isEventMinter(uint256 eventId, address account) view returns(bool) -func (_POAPContract *POAPContractCaller) IsEventMinter(opts *bind.CallOpts, eventId *big.Int, account common.Address) (bool, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "isEventMinter", eventId, account) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsEventMinter is a free data retrieval call binding the contract method 0x28db38b4. -// -// Solidity: function isEventMinter(uint256 eventId, address account) view returns(bool) -func (_POAPContract *POAPContractSession) IsEventMinter(eventId *big.Int, account common.Address) (bool, error) { - return _POAPContract.Contract.IsEventMinter(&_POAPContract.CallOpts, eventId, account) -} - -// IsEventMinter is a free data retrieval call binding the contract method 0x28db38b4. -// -// Solidity: function isEventMinter(uint256 eventId, address account) view returns(bool) -func (_POAPContract *POAPContractCallerSession) IsEventMinter(eventId *big.Int, account common.Address) (bool, error) { - return _POAPContract.Contract.IsEventMinter(&_POAPContract.CallOpts, eventId, account) -} - -// IsFrozen is a free data retrieval call binding the contract method 0xa0894799. -// -// Solidity: function isFrozen(uint256 tokenId) view returns(bool) -func (_POAPContract *POAPContractCaller) IsFrozen(opts *bind.CallOpts, tokenId *big.Int) (bool, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "isFrozen", tokenId) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsFrozen is a free data retrieval call binding the contract method 0xa0894799. -// -// Solidity: function isFrozen(uint256 tokenId) view returns(bool) -func (_POAPContract *POAPContractSession) IsFrozen(tokenId *big.Int) (bool, error) { - return _POAPContract.Contract.IsFrozen(&_POAPContract.CallOpts, tokenId) -} - -// IsFrozen is a free data retrieval call binding the contract method 0xa0894799. -// -// Solidity: function isFrozen(uint256 tokenId) view returns(bool) -func (_POAPContract *POAPContractCallerSession) IsFrozen(tokenId *big.Int) (bool, error) { - return _POAPContract.Contract.IsFrozen(&_POAPContract.CallOpts, tokenId) -} - -// LastId is a free data retrieval call binding the contract method 0xc1292cc3. -// -// Solidity: function lastId() view returns(uint256) -func (_POAPContract *POAPContractCaller) LastId(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "lastId") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// LastId is a free data retrieval call binding the contract method 0xc1292cc3. -// -// Solidity: function lastId() view returns(uint256) -func (_POAPContract *POAPContractSession) LastId() (*big.Int, error) { - return _POAPContract.Contract.LastId(&_POAPContract.CallOpts) -} - -// LastId is a free data retrieval call binding the contract method 0xc1292cc3. -// -// Solidity: function lastId() view returns(uint256) -func (_POAPContract *POAPContractCallerSession) LastId() (*big.Int, error) { - return _POAPContract.Contract.LastId(&_POAPContract.CallOpts) -} - -// Name is a free data retrieval call binding the contract method 0x06fdde03. -// -// Solidity: function name() view returns(string) -func (_POAPContract *POAPContractCaller) Name(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "name") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// Name is a free data retrieval call binding the contract method 0x06fdde03. -// -// Solidity: function name() view returns(string) -func (_POAPContract *POAPContractSession) Name() (string, error) { - return _POAPContract.Contract.Name(&_POAPContract.CallOpts) -} - -// Name is a free data retrieval call binding the contract method 0x06fdde03. -// -// Solidity: function name() view returns(string) -func (_POAPContract *POAPContractCallerSession) Name() (string, error) { - return _POAPContract.Contract.Name(&_POAPContract.CallOpts) -} - -// OwnerOf is a free data retrieval call binding the contract method 0x6352211e. -// -// Solidity: function ownerOf(uint256 tokenId) view returns(address) -func (_POAPContract *POAPContractCaller) OwnerOf(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "ownerOf", tokenId) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// OwnerOf is a free data retrieval call binding the contract method 0x6352211e. -// -// Solidity: function ownerOf(uint256 tokenId) view returns(address) -func (_POAPContract *POAPContractSession) OwnerOf(tokenId *big.Int) (common.Address, error) { - return _POAPContract.Contract.OwnerOf(&_POAPContract.CallOpts, tokenId) -} - -// OwnerOf is a free data retrieval call binding the contract method 0x6352211e. -// -// Solidity: function ownerOf(uint256 tokenId) view returns(address) -func (_POAPContract *POAPContractCallerSession) OwnerOf(tokenId *big.Int) (common.Address, error) { - return _POAPContract.Contract.OwnerOf(&_POAPContract.CallOpts, tokenId) -} - -// Paused is a free data retrieval call binding the contract method 0x5c975abb. -// -// Solidity: function paused() view returns(bool) -func (_POAPContract *POAPContractCaller) Paused(opts *bind.CallOpts) (bool, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "paused") - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// Paused is a free data retrieval call binding the contract method 0x5c975abb. -// -// Solidity: function paused() view returns(bool) -func (_POAPContract *POAPContractSession) Paused() (bool, error) { - return _POAPContract.Contract.Paused(&_POAPContract.CallOpts) -} - -// Paused is a free data retrieval call binding the contract method 0x5c975abb. -// -// Solidity: function paused() view returns(bool) -func (_POAPContract *POAPContractCallerSession) Paused() (bool, error) { - return _POAPContract.Contract.Paused(&_POAPContract.CallOpts) -} - -// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. -// -// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) -func (_POAPContract *POAPContractCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "supportsInterface", interfaceId) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. -// -// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) -func (_POAPContract *POAPContractSession) SupportsInterface(interfaceId [4]byte) (bool, error) { - return _POAPContract.Contract.SupportsInterface(&_POAPContract.CallOpts, interfaceId) -} - -// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. -// -// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) -func (_POAPContract *POAPContractCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { - return _POAPContract.Contract.SupportsInterface(&_POAPContract.CallOpts, interfaceId) -} - -// Symbol is a free data retrieval call binding the contract method 0x95d89b41. -// -// Solidity: function symbol() view returns(string) -func (_POAPContract *POAPContractCaller) Symbol(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "symbol") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// Symbol is a free data retrieval call binding the contract method 0x95d89b41. -// -// Solidity: function symbol() view returns(string) -func (_POAPContract *POAPContractSession) Symbol() (string, error) { - return _POAPContract.Contract.Symbol(&_POAPContract.CallOpts) -} - -// Symbol is a free data retrieval call binding the contract method 0x95d89b41. -// -// Solidity: function symbol() view returns(string) -func (_POAPContract *POAPContractCallerSession) Symbol() (string, error) { - return _POAPContract.Contract.Symbol(&_POAPContract.CallOpts) -} - -// TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. -// -// Solidity: function tokenByIndex(uint256 index) view returns(uint256) -func (_POAPContract *POAPContractCaller) TokenByIndex(opts *bind.CallOpts, index *big.Int) (*big.Int, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "tokenByIndex", index) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. -// -// Solidity: function tokenByIndex(uint256 index) view returns(uint256) -func (_POAPContract *POAPContractSession) TokenByIndex(index *big.Int) (*big.Int, error) { - return _POAPContract.Contract.TokenByIndex(&_POAPContract.CallOpts, index) -} - -// TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. -// -// Solidity: function tokenByIndex(uint256 index) view returns(uint256) -func (_POAPContract *POAPContractCallerSession) TokenByIndex(index *big.Int) (*big.Int, error) { - return _POAPContract.Contract.TokenByIndex(&_POAPContract.CallOpts, index) -} - -// TokenDetailsOfOwnerByIndex is a free data retrieval call binding the contract method 0x67e971ce. -// -// Solidity: function tokenDetailsOfOwnerByIndex(address owner, uint256 index) view returns(uint256 tokenId, uint256 eventId) -func (_POAPContract *POAPContractCaller) TokenDetailsOfOwnerByIndex(opts *bind.CallOpts, owner common.Address, index *big.Int) (struct { - TokenId *big.Int - EventId *big.Int -}, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "tokenDetailsOfOwnerByIndex", owner, index) - - outstruct := new(struct { - TokenId *big.Int - EventId *big.Int - }) - if err != nil { - return *outstruct, err - } - - outstruct.TokenId = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - outstruct.EventId = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - - return *outstruct, err - -} - -// TokenDetailsOfOwnerByIndex is a free data retrieval call binding the contract method 0x67e971ce. -// -// Solidity: function tokenDetailsOfOwnerByIndex(address owner, uint256 index) view returns(uint256 tokenId, uint256 eventId) -func (_POAPContract *POAPContractSession) TokenDetailsOfOwnerByIndex(owner common.Address, index *big.Int) (struct { - TokenId *big.Int - EventId *big.Int -}, error) { - return _POAPContract.Contract.TokenDetailsOfOwnerByIndex(&_POAPContract.CallOpts, owner, index) -} - -// TokenDetailsOfOwnerByIndex is a free data retrieval call binding the contract method 0x67e971ce. -// -// Solidity: function tokenDetailsOfOwnerByIndex(address owner, uint256 index) view returns(uint256 tokenId, uint256 eventId) -func (_POAPContract *POAPContractCallerSession) TokenDetailsOfOwnerByIndex(owner common.Address, index *big.Int) (struct { - TokenId *big.Int - EventId *big.Int -}, error) { - return _POAPContract.Contract.TokenDetailsOfOwnerByIndex(&_POAPContract.CallOpts, owner, index) -} - -// TokenEvent is a free data retrieval call binding the contract method 0x127a5298. -// -// Solidity: function tokenEvent(uint256 tokenId) view returns(uint256) -func (_POAPContract *POAPContractCaller) TokenEvent(opts *bind.CallOpts, tokenId *big.Int) (*big.Int, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "tokenEvent", tokenId) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// TokenEvent is a free data retrieval call binding the contract method 0x127a5298. -// -// Solidity: function tokenEvent(uint256 tokenId) view returns(uint256) -func (_POAPContract *POAPContractSession) TokenEvent(tokenId *big.Int) (*big.Int, error) { - return _POAPContract.Contract.TokenEvent(&_POAPContract.CallOpts, tokenId) -} - -// TokenEvent is a free data retrieval call binding the contract method 0x127a5298. -// -// Solidity: function tokenEvent(uint256 tokenId) view returns(uint256) -func (_POAPContract *POAPContractCallerSession) TokenEvent(tokenId *big.Int) (*big.Int, error) { - return _POAPContract.Contract.TokenEvent(&_POAPContract.CallOpts, tokenId) -} - -// TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. -// -// Solidity: function tokenOfOwnerByIndex(address owner, uint256 index) view returns(uint256) -func (_POAPContract *POAPContractCaller) TokenOfOwnerByIndex(opts *bind.CallOpts, owner common.Address, index *big.Int) (*big.Int, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "tokenOfOwnerByIndex", owner, index) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. -// -// Solidity: function tokenOfOwnerByIndex(address owner, uint256 index) view returns(uint256) -func (_POAPContract *POAPContractSession) TokenOfOwnerByIndex(owner common.Address, index *big.Int) (*big.Int, error) { - return _POAPContract.Contract.TokenOfOwnerByIndex(&_POAPContract.CallOpts, owner, index) -} - -// TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. -// -// Solidity: function tokenOfOwnerByIndex(address owner, uint256 index) view returns(uint256) -func (_POAPContract *POAPContractCallerSession) TokenOfOwnerByIndex(owner common.Address, index *big.Int) (*big.Int, error) { - return _POAPContract.Contract.TokenOfOwnerByIndex(&_POAPContract.CallOpts, owner, index) -} - -// TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. -// -// Solidity: function tokenURI(uint256 tokenId) view returns(string) -func (_POAPContract *POAPContractCaller) TokenURI(opts *bind.CallOpts, tokenId *big.Int) (string, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "tokenURI", tokenId) - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. -// -// Solidity: function tokenURI(uint256 tokenId) view returns(string) -func (_POAPContract *POAPContractSession) TokenURI(tokenId *big.Int) (string, error) { - return _POAPContract.Contract.TokenURI(&_POAPContract.CallOpts, tokenId) -} - -// TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. -// -// Solidity: function tokenURI(uint256 tokenId) view returns(string) -func (_POAPContract *POAPContractCallerSession) TokenURI(tokenId *big.Int) (string, error) { - return _POAPContract.Contract.TokenURI(&_POAPContract.CallOpts, tokenId) -} - -// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. -// -// Solidity: function totalSupply() view returns(uint256) -func (_POAPContract *POAPContractCaller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _POAPContract.contract.Call(opts, &out, "totalSupply") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. -// -// Solidity: function totalSupply() view returns(uint256) -func (_POAPContract *POAPContractSession) TotalSupply() (*big.Int, error) { - return _POAPContract.Contract.TotalSupply(&_POAPContract.CallOpts) -} - -// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. -// -// Solidity: function totalSupply() view returns(uint256) -func (_POAPContract *POAPContractCallerSession) TotalSupply() (*big.Int, error) { - return _POAPContract.Contract.TotalSupply(&_POAPContract.CallOpts) -} - -// AddAdmin is a paid mutator transaction binding the contract method 0x70480275. -// -// Solidity: function addAdmin(address account) returns() -func (_POAPContract *POAPContractTransactor) AddAdmin(opts *bind.TransactOpts, account common.Address) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "addAdmin", account) -} - -// AddAdmin is a paid mutator transaction binding the contract method 0x70480275. -// -// Solidity: function addAdmin(address account) returns() -func (_POAPContract *POAPContractSession) AddAdmin(account common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.AddAdmin(&_POAPContract.TransactOpts, account) -} - -// AddAdmin is a paid mutator transaction binding the contract method 0x70480275. -// -// Solidity: function addAdmin(address account) returns() -func (_POAPContract *POAPContractTransactorSession) AddAdmin(account common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.AddAdmin(&_POAPContract.TransactOpts, account) -} - -// AddEventMinter is a paid mutator transaction binding the contract method 0x9cd3cad6. -// -// Solidity: function addEventMinter(uint256 eventId, address account) returns() -func (_POAPContract *POAPContractTransactor) AddEventMinter(opts *bind.TransactOpts, eventId *big.Int, account common.Address) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "addEventMinter", eventId, account) -} - -// AddEventMinter is a paid mutator transaction binding the contract method 0x9cd3cad6. -// -// Solidity: function addEventMinter(uint256 eventId, address account) returns() -func (_POAPContract *POAPContractSession) AddEventMinter(eventId *big.Int, account common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.AddEventMinter(&_POAPContract.TransactOpts, eventId, account) -} - -// AddEventMinter is a paid mutator transaction binding the contract method 0x9cd3cad6. -// -// Solidity: function addEventMinter(uint256 eventId, address account) returns() -func (_POAPContract *POAPContractTransactorSession) AddEventMinter(eventId *big.Int, account common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.AddEventMinter(&_POAPContract.TransactOpts, eventId, account) -} - -// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. -// -// Solidity: function approve(address to, uint256 tokenId) returns() -func (_POAPContract *POAPContractTransactor) Approve(opts *bind.TransactOpts, to common.Address, tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "approve", to, tokenId) -} - -// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. -// -// Solidity: function approve(address to, uint256 tokenId) returns() -func (_POAPContract *POAPContractSession) Approve(to common.Address, tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.Approve(&_POAPContract.TransactOpts, to, tokenId) -} - -// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. -// -// Solidity: function approve(address to, uint256 tokenId) returns() -func (_POAPContract *POAPContractTransactorSession) Approve(to common.Address, tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.Approve(&_POAPContract.TransactOpts, to, tokenId) -} - -// Burn is a paid mutator transaction binding the contract method 0x42966c68. -// -// Solidity: function burn(uint256 tokenId) returns() -func (_POAPContract *POAPContractTransactor) Burn(opts *bind.TransactOpts, tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "burn", tokenId) -} - -// Burn is a paid mutator transaction binding the contract method 0x42966c68. -// -// Solidity: function burn(uint256 tokenId) returns() -func (_POAPContract *POAPContractSession) Burn(tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.Burn(&_POAPContract.TransactOpts, tokenId) -} - -// Burn is a paid mutator transaction binding the contract method 0x42966c68. -// -// Solidity: function burn(uint256 tokenId) returns() -func (_POAPContract *POAPContractTransactorSession) Burn(tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.Burn(&_POAPContract.TransactOpts, tokenId) -} - -// Freeze is a paid mutator transaction binding the contract method 0xd7a78db8. -// -// Solidity: function freeze(uint256 tokenId) returns() -func (_POAPContract *POAPContractTransactor) Freeze(opts *bind.TransactOpts, tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "freeze", tokenId) -} - -// Freeze is a paid mutator transaction binding the contract method 0xd7a78db8. -// -// Solidity: function freeze(uint256 tokenId) returns() -func (_POAPContract *POAPContractSession) Freeze(tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.Freeze(&_POAPContract.TransactOpts, tokenId) -} - -// Freeze is a paid mutator transaction binding the contract method 0xd7a78db8. -// -// Solidity: function freeze(uint256 tokenId) returns() -func (_POAPContract *POAPContractTransactorSession) Freeze(tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.Freeze(&_POAPContract.TransactOpts, tokenId) -} - -// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. -// -// Solidity: function initialize() returns() -func (_POAPContract *POAPContractTransactor) Initialize(opts *bind.TransactOpts) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "initialize") -} - -// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. -// -// Solidity: function initialize() returns() -func (_POAPContract *POAPContractSession) Initialize() (*types.Transaction, error) { - return _POAPContract.Contract.Initialize(&_POAPContract.TransactOpts) -} - -// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. -// -// Solidity: function initialize() returns() -func (_POAPContract *POAPContractTransactorSession) Initialize() (*types.Transaction, error) { - return _POAPContract.Contract.Initialize(&_POAPContract.TransactOpts) -} - -// Initialize0 is a paid mutator transaction binding the contract method 0x8d232094. -// -// Solidity: function initialize(string __name, string __symbol, string __baseURI, address[] admins) returns() -func (_POAPContract *POAPContractTransactor) Initialize0(opts *bind.TransactOpts, __name string, __symbol string, __baseURI string, admins []common.Address) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "initialize0", __name, __symbol, __baseURI, admins) -} - -// Initialize0 is a paid mutator transaction binding the contract method 0x8d232094. -// -// Solidity: function initialize(string __name, string __symbol, string __baseURI, address[] admins) returns() -func (_POAPContract *POAPContractSession) Initialize0(__name string, __symbol string, __baseURI string, admins []common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.Initialize0(&_POAPContract.TransactOpts, __name, __symbol, __baseURI, admins) -} - -// Initialize0 is a paid mutator transaction binding the contract method 0x8d232094. -// -// Solidity: function initialize(string __name, string __symbol, string __baseURI, address[] admins) returns() -func (_POAPContract *POAPContractTransactorSession) Initialize0(__name string, __symbol string, __baseURI string, admins []common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.Initialize0(&_POAPContract.TransactOpts, __name, __symbol, __baseURI, admins) -} - -// Initialize1 is a paid mutator transaction binding the contract method 0xc4d66de8. -// -// Solidity: function initialize(address sender) returns() -func (_POAPContract *POAPContractTransactor) Initialize1(opts *bind.TransactOpts, sender common.Address) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "initialize1", sender) -} - -// Initialize1 is a paid mutator transaction binding the contract method 0xc4d66de8. -// -// Solidity: function initialize(address sender) returns() -func (_POAPContract *POAPContractSession) Initialize1(sender common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.Initialize1(&_POAPContract.TransactOpts, sender) -} - -// Initialize1 is a paid mutator transaction binding the contract method 0xc4d66de8. -// -// Solidity: function initialize(address sender) returns() -func (_POAPContract *POAPContractTransactorSession) Initialize1(sender common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.Initialize1(&_POAPContract.TransactOpts, sender) -} - -// MintEventToManyUsers is a paid mutator transaction binding the contract method 0x278d9c41. -// -// Solidity: function mintEventToManyUsers(uint256 eventId, address[] to) returns(bool) -func (_POAPContract *POAPContractTransactor) MintEventToManyUsers(opts *bind.TransactOpts, eventId *big.Int, to []common.Address) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "mintEventToManyUsers", eventId, to) -} - -// MintEventToManyUsers is a paid mutator transaction binding the contract method 0x278d9c41. -// -// Solidity: function mintEventToManyUsers(uint256 eventId, address[] to) returns(bool) -func (_POAPContract *POAPContractSession) MintEventToManyUsers(eventId *big.Int, to []common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.MintEventToManyUsers(&_POAPContract.TransactOpts, eventId, to) -} - -// MintEventToManyUsers is a paid mutator transaction binding the contract method 0x278d9c41. -// -// Solidity: function mintEventToManyUsers(uint256 eventId, address[] to) returns(bool) -func (_POAPContract *POAPContractTransactorSession) MintEventToManyUsers(eventId *big.Int, to []common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.MintEventToManyUsers(&_POAPContract.TransactOpts, eventId, to) -} - -// MintToken is a paid mutator transaction binding the contract method 0xa140ae23. -// -// Solidity: function mintToken(uint256 eventId, address to) returns(bool) -func (_POAPContract *POAPContractTransactor) MintToken(opts *bind.TransactOpts, eventId *big.Int, to common.Address) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "mintToken", eventId, to) -} - -// MintToken is a paid mutator transaction binding the contract method 0xa140ae23. -// -// Solidity: function mintToken(uint256 eventId, address to) returns(bool) -func (_POAPContract *POAPContractSession) MintToken(eventId *big.Int, to common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.MintToken(&_POAPContract.TransactOpts, eventId, to) -} - -// MintToken is a paid mutator transaction binding the contract method 0xa140ae23. -// -// Solidity: function mintToken(uint256 eventId, address to) returns(bool) -func (_POAPContract *POAPContractTransactorSession) MintToken(eventId *big.Int, to common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.MintToken(&_POAPContract.TransactOpts, eventId, to) -} - -// MintUserToManyEvents is a paid mutator transaction binding the contract method 0xf980f3dc. -// -// Solidity: function mintUserToManyEvents(uint256[] eventIds, address to) returns(bool) -func (_POAPContract *POAPContractTransactor) MintUserToManyEvents(opts *bind.TransactOpts, eventIds []*big.Int, to common.Address) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "mintUserToManyEvents", eventIds, to) -} - -// MintUserToManyEvents is a paid mutator transaction binding the contract method 0xf980f3dc. -// -// Solidity: function mintUserToManyEvents(uint256[] eventIds, address to) returns(bool) -func (_POAPContract *POAPContractSession) MintUserToManyEvents(eventIds []*big.Int, to common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.MintUserToManyEvents(&_POAPContract.TransactOpts, eventIds, to) -} - -// MintUserToManyEvents is a paid mutator transaction binding the contract method 0xf980f3dc. -// -// Solidity: function mintUserToManyEvents(uint256[] eventIds, address to) returns(bool) -func (_POAPContract *POAPContractTransactorSession) MintUserToManyEvents(eventIds []*big.Int, to common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.MintUserToManyEvents(&_POAPContract.TransactOpts, eventIds, to) -} - -// Pause is a paid mutator transaction binding the contract method 0x8456cb59. -// -// Solidity: function pause() returns() -func (_POAPContract *POAPContractTransactor) Pause(opts *bind.TransactOpts) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "pause") -} - -// Pause is a paid mutator transaction binding the contract method 0x8456cb59. -// -// Solidity: function pause() returns() -func (_POAPContract *POAPContractSession) Pause() (*types.Transaction, error) { - return _POAPContract.Contract.Pause(&_POAPContract.TransactOpts) -} - -// Pause is a paid mutator transaction binding the contract method 0x8456cb59. -// -// Solidity: function pause() returns() -func (_POAPContract *POAPContractTransactorSession) Pause() (*types.Transaction, error) { - return _POAPContract.Contract.Pause(&_POAPContract.TransactOpts) -} - -// RemoveEventMinter is a paid mutator transaction binding the contract method 0x166c4b05. -// -// Solidity: function removeEventMinter(uint256 eventId, address account) returns() -func (_POAPContract *POAPContractTransactor) RemoveEventMinter(opts *bind.TransactOpts, eventId *big.Int, account common.Address) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "removeEventMinter", eventId, account) -} - -// RemoveEventMinter is a paid mutator transaction binding the contract method 0x166c4b05. -// -// Solidity: function removeEventMinter(uint256 eventId, address account) returns() -func (_POAPContract *POAPContractSession) RemoveEventMinter(eventId *big.Int, account common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.RemoveEventMinter(&_POAPContract.TransactOpts, eventId, account) -} - -// RemoveEventMinter is a paid mutator transaction binding the contract method 0x166c4b05. -// -// Solidity: function removeEventMinter(uint256 eventId, address account) returns() -func (_POAPContract *POAPContractTransactorSession) RemoveEventMinter(eventId *big.Int, account common.Address) (*types.Transaction, error) { - return _POAPContract.Contract.RemoveEventMinter(&_POAPContract.TransactOpts, eventId, account) -} - -// RenounceAdmin is a paid mutator transaction binding the contract method 0x8bad0c0a. -// -// Solidity: function renounceAdmin() returns() -func (_POAPContract *POAPContractTransactor) RenounceAdmin(opts *bind.TransactOpts) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "renounceAdmin") -} - -// RenounceAdmin is a paid mutator transaction binding the contract method 0x8bad0c0a. -// -// Solidity: function renounceAdmin() returns() -func (_POAPContract *POAPContractSession) RenounceAdmin() (*types.Transaction, error) { - return _POAPContract.Contract.RenounceAdmin(&_POAPContract.TransactOpts) -} - -// RenounceAdmin is a paid mutator transaction binding the contract method 0x8bad0c0a. -// -// Solidity: function renounceAdmin() returns() -func (_POAPContract *POAPContractTransactorSession) RenounceAdmin() (*types.Transaction, error) { - return _POAPContract.Contract.RenounceAdmin(&_POAPContract.TransactOpts) -} - -// RenounceEventMinter is a paid mutator transaction binding the contract method 0x02c37ddc. -// -// Solidity: function renounceEventMinter(uint256 eventId) returns() -func (_POAPContract *POAPContractTransactor) RenounceEventMinter(opts *bind.TransactOpts, eventId *big.Int) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "renounceEventMinter", eventId) -} - -// RenounceEventMinter is a paid mutator transaction binding the contract method 0x02c37ddc. -// -// Solidity: function renounceEventMinter(uint256 eventId) returns() -func (_POAPContract *POAPContractSession) RenounceEventMinter(eventId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.RenounceEventMinter(&_POAPContract.TransactOpts, eventId) -} - -// RenounceEventMinter is a paid mutator transaction binding the contract method 0x02c37ddc. -// -// Solidity: function renounceEventMinter(uint256 eventId) returns() -func (_POAPContract *POAPContractTransactorSession) RenounceEventMinter(eventId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.RenounceEventMinter(&_POAPContract.TransactOpts, eventId) -} - -// SafeTransferFrom is a paid mutator transaction binding the contract method 0x42842e0e. -// -// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId) returns() -func (_POAPContract *POAPContractTransactor) SafeTransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "safeTransferFrom", from, to, tokenId) -} - -// SafeTransferFrom is a paid mutator transaction binding the contract method 0x42842e0e. -// -// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId) returns() -func (_POAPContract *POAPContractSession) SafeTransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.SafeTransferFrom(&_POAPContract.TransactOpts, from, to, tokenId) -} - -// SafeTransferFrom is a paid mutator transaction binding the contract method 0x42842e0e. -// -// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId) returns() -func (_POAPContract *POAPContractTransactorSession) SafeTransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.SafeTransferFrom(&_POAPContract.TransactOpts, from, to, tokenId) -} - -// SafeTransferFrom0 is a paid mutator transaction binding the contract method 0xb88d4fde. -// -// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId, bytes _data) returns() -func (_POAPContract *POAPContractTransactor) SafeTransferFrom0(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int, _data []byte) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "safeTransferFrom0", from, to, tokenId, _data) -} - -// SafeTransferFrom0 is a paid mutator transaction binding the contract method 0xb88d4fde. -// -// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId, bytes _data) returns() -func (_POAPContract *POAPContractSession) SafeTransferFrom0(from common.Address, to common.Address, tokenId *big.Int, _data []byte) (*types.Transaction, error) { - return _POAPContract.Contract.SafeTransferFrom0(&_POAPContract.TransactOpts, from, to, tokenId, _data) -} - -// SafeTransferFrom0 is a paid mutator transaction binding the contract method 0xb88d4fde. -// -// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId, bytes _data) returns() -func (_POAPContract *POAPContractTransactorSession) SafeTransferFrom0(from common.Address, to common.Address, tokenId *big.Int, _data []byte) (*types.Transaction, error) { - return _POAPContract.Contract.SafeTransferFrom0(&_POAPContract.TransactOpts, from, to, tokenId, _data) -} - -// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. -// -// Solidity: function setApprovalForAll(address to, bool approved) returns() -func (_POAPContract *POAPContractTransactor) SetApprovalForAll(opts *bind.TransactOpts, to common.Address, approved bool) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "setApprovalForAll", to, approved) -} - -// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. -// -// Solidity: function setApprovalForAll(address to, bool approved) returns() -func (_POAPContract *POAPContractSession) SetApprovalForAll(to common.Address, approved bool) (*types.Transaction, error) { - return _POAPContract.Contract.SetApprovalForAll(&_POAPContract.TransactOpts, to, approved) -} - -// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. -// -// Solidity: function setApprovalForAll(address to, bool approved) returns() -func (_POAPContract *POAPContractTransactorSession) SetApprovalForAll(to common.Address, approved bool) (*types.Transaction, error) { - return _POAPContract.Contract.SetApprovalForAll(&_POAPContract.TransactOpts, to, approved) -} - -// SetBaseURI is a paid mutator transaction binding the contract method 0x55f804b3. -// -// Solidity: function setBaseURI(string baseURI) returns() -func (_POAPContract *POAPContractTransactor) SetBaseURI(opts *bind.TransactOpts, baseURI string) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "setBaseURI", baseURI) -} - -// SetBaseURI is a paid mutator transaction binding the contract method 0x55f804b3. -// -// Solidity: function setBaseURI(string baseURI) returns() -func (_POAPContract *POAPContractSession) SetBaseURI(baseURI string) (*types.Transaction, error) { - return _POAPContract.Contract.SetBaseURI(&_POAPContract.TransactOpts, baseURI) -} - -// SetBaseURI is a paid mutator transaction binding the contract method 0x55f804b3. -// -// Solidity: function setBaseURI(string baseURI) returns() -func (_POAPContract *POAPContractTransactorSession) SetBaseURI(baseURI string) (*types.Transaction, error) { - return _POAPContract.Contract.SetBaseURI(&_POAPContract.TransactOpts, baseURI) -} - -// SetFreezeDuration is a paid mutator transaction binding the contract method 0x6ca2aa95. -// -// Solidity: function setFreezeDuration(uint256 time) returns() -func (_POAPContract *POAPContractTransactor) SetFreezeDuration(opts *bind.TransactOpts, time *big.Int) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "setFreezeDuration", time) -} - -// SetFreezeDuration is a paid mutator transaction binding the contract method 0x6ca2aa95. -// -// Solidity: function setFreezeDuration(uint256 time) returns() -func (_POAPContract *POAPContractSession) SetFreezeDuration(time *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.SetFreezeDuration(&_POAPContract.TransactOpts, time) -} - -// SetFreezeDuration is a paid mutator transaction binding the contract method 0x6ca2aa95. -// -// Solidity: function setFreezeDuration(uint256 time) returns() -func (_POAPContract *POAPContractTransactorSession) SetFreezeDuration(time *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.SetFreezeDuration(&_POAPContract.TransactOpts, time) -} - -// SetLastId is a paid mutator transaction binding the contract method 0x1a27e85f. -// -// Solidity: function setLastId(uint256 newLastId) returns() -func (_POAPContract *POAPContractTransactor) SetLastId(opts *bind.TransactOpts, newLastId *big.Int) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "setLastId", newLastId) -} - -// SetLastId is a paid mutator transaction binding the contract method 0x1a27e85f. -// -// Solidity: function setLastId(uint256 newLastId) returns() -func (_POAPContract *POAPContractSession) SetLastId(newLastId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.SetLastId(&_POAPContract.TransactOpts, newLastId) -} - -// SetLastId is a paid mutator transaction binding the contract method 0x1a27e85f. -// -// Solidity: function setLastId(uint256 newLastId) returns() -func (_POAPContract *POAPContractTransactorSession) SetLastId(newLastId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.SetLastId(&_POAPContract.TransactOpts, newLastId) -} - -// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. -// -// Solidity: function transferFrom(address from, address to, uint256 tokenId) returns() -func (_POAPContract *POAPContractTransactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "transferFrom", from, to, tokenId) -} - -// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. -// -// Solidity: function transferFrom(address from, address to, uint256 tokenId) returns() -func (_POAPContract *POAPContractSession) TransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.TransferFrom(&_POAPContract.TransactOpts, from, to, tokenId) -} - -// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. -// -// Solidity: function transferFrom(address from, address to, uint256 tokenId) returns() -func (_POAPContract *POAPContractTransactorSession) TransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.TransferFrom(&_POAPContract.TransactOpts, from, to, tokenId) -} - -// Unfreeze is a paid mutator transaction binding the contract method 0x6623fc46. -// -// Solidity: function unfreeze(uint256 tokenId) returns() -func (_POAPContract *POAPContractTransactor) Unfreeze(opts *bind.TransactOpts, tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "unfreeze", tokenId) -} - -// Unfreeze is a paid mutator transaction binding the contract method 0x6623fc46. -// -// Solidity: function unfreeze(uint256 tokenId) returns() -func (_POAPContract *POAPContractSession) Unfreeze(tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.Unfreeze(&_POAPContract.TransactOpts, tokenId) -} - -// Unfreeze is a paid mutator transaction binding the contract method 0x6623fc46. -// -// Solidity: function unfreeze(uint256 tokenId) returns() -func (_POAPContract *POAPContractTransactorSession) Unfreeze(tokenId *big.Int) (*types.Transaction, error) { - return _POAPContract.Contract.Unfreeze(&_POAPContract.TransactOpts, tokenId) -} - -// Unpause is a paid mutator transaction binding the contract method 0x3f4ba83a. -// -// Solidity: function unpause() returns() -func (_POAPContract *POAPContractTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) { - return _POAPContract.contract.Transact(opts, "unpause") -} - -// Unpause is a paid mutator transaction binding the contract method 0x3f4ba83a. -// -// Solidity: function unpause() returns() -func (_POAPContract *POAPContractSession) Unpause() (*types.Transaction, error) { - return _POAPContract.Contract.Unpause(&_POAPContract.TransactOpts) -} - -// Unpause is a paid mutator transaction binding the contract method 0x3f4ba83a. -// -// Solidity: function unpause() returns() -func (_POAPContract *POAPContractTransactorSession) Unpause() (*types.Transaction, error) { - return _POAPContract.Contract.Unpause(&_POAPContract.TransactOpts) -} - -// POAPContractAdminAddedIterator is returned from FilterAdminAdded and is used to iterate over the raw logs and unpacked data for AdminAdded events raised by the POAPContract contract. -type POAPContractAdminAddedIterator struct { - Event *POAPContractAdminAdded // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *POAPContractAdminAddedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(POAPContractAdminAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(POAPContractAdminAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *POAPContractAdminAddedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *POAPContractAdminAddedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// POAPContractAdminAdded represents a AdminAdded event raised by the POAPContract contract. -type POAPContractAdminAdded struct { - Account common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAdminAdded is a free log retrieval operation binding the contract event 0x44d6d25963f097ad14f29f06854a01f575648a1ef82f30e562ccd3889717e339. -// -// Solidity: event AdminAdded(address indexed account) -func (_POAPContract *POAPContractFilterer) FilterAdminAdded(opts *bind.FilterOpts, account []common.Address) (*POAPContractAdminAddedIterator, error) { - - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - - logs, sub, err := _POAPContract.contract.FilterLogs(opts, "AdminAdded", accountRule) - if err != nil { - return nil, err - } - return &POAPContractAdminAddedIterator{contract: _POAPContract.contract, event: "AdminAdded", logs: logs, sub: sub}, nil -} - -// WatchAdminAdded is a free log subscription operation binding the contract event 0x44d6d25963f097ad14f29f06854a01f575648a1ef82f30e562ccd3889717e339. -// -// Solidity: event AdminAdded(address indexed account) -func (_POAPContract *POAPContractFilterer) WatchAdminAdded(opts *bind.WatchOpts, sink chan<- *POAPContractAdminAdded, account []common.Address) (event.Subscription, error) { - - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - - logs, sub, err := _POAPContract.contract.WatchLogs(opts, "AdminAdded", accountRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(POAPContractAdminAdded) - if err := _POAPContract.contract.UnpackLog(event, "AdminAdded", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAdminAdded is a log parse operation binding the contract event 0x44d6d25963f097ad14f29f06854a01f575648a1ef82f30e562ccd3889717e339. -// -// Solidity: event AdminAdded(address indexed account) -func (_POAPContract *POAPContractFilterer) ParseAdminAdded(log types.Log) (*POAPContractAdminAdded, error) { - event := new(POAPContractAdminAdded) - if err := _POAPContract.contract.UnpackLog(event, "AdminAdded", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// POAPContractAdminRemovedIterator is returned from FilterAdminRemoved and is used to iterate over the raw logs and unpacked data for AdminRemoved events raised by the POAPContract contract. -type POAPContractAdminRemovedIterator struct { - Event *POAPContractAdminRemoved // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *POAPContractAdminRemovedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(POAPContractAdminRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(POAPContractAdminRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *POAPContractAdminRemovedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *POAPContractAdminRemovedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// POAPContractAdminRemoved represents a AdminRemoved event raised by the POAPContract contract. -type POAPContractAdminRemoved struct { - Account common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAdminRemoved is a free log retrieval operation binding the contract event 0xa3b62bc36326052d97ea62d63c3d60308ed4c3ea8ac079dd8499f1e9c4f80c0f. -// -// Solidity: event AdminRemoved(address indexed account) -func (_POAPContract *POAPContractFilterer) FilterAdminRemoved(opts *bind.FilterOpts, account []common.Address) (*POAPContractAdminRemovedIterator, error) { - - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - - logs, sub, err := _POAPContract.contract.FilterLogs(opts, "AdminRemoved", accountRule) - if err != nil { - return nil, err - } - return &POAPContractAdminRemovedIterator{contract: _POAPContract.contract, event: "AdminRemoved", logs: logs, sub: sub}, nil -} - -// WatchAdminRemoved is a free log subscription operation binding the contract event 0xa3b62bc36326052d97ea62d63c3d60308ed4c3ea8ac079dd8499f1e9c4f80c0f. -// -// Solidity: event AdminRemoved(address indexed account) -func (_POAPContract *POAPContractFilterer) WatchAdminRemoved(opts *bind.WatchOpts, sink chan<- *POAPContractAdminRemoved, account []common.Address) (event.Subscription, error) { - - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - - logs, sub, err := _POAPContract.contract.WatchLogs(opts, "AdminRemoved", accountRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(POAPContractAdminRemoved) - if err := _POAPContract.contract.UnpackLog(event, "AdminRemoved", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAdminRemoved is a log parse operation binding the contract event 0xa3b62bc36326052d97ea62d63c3d60308ed4c3ea8ac079dd8499f1e9c4f80c0f. -// -// Solidity: event AdminRemoved(address indexed account) -func (_POAPContract *POAPContractFilterer) ParseAdminRemoved(log types.Log) (*POAPContractAdminRemoved, error) { - event := new(POAPContractAdminRemoved) - if err := _POAPContract.contract.UnpackLog(event, "AdminRemoved", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// POAPContractApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the POAPContract contract. -type POAPContractApprovalIterator struct { - Event *POAPContractApproval // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *POAPContractApprovalIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(POAPContractApproval) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(POAPContractApproval) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *POAPContractApprovalIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *POAPContractApprovalIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// POAPContractApproval represents a Approval event raised by the POAPContract contract. -type POAPContractApproval struct { - Owner common.Address - Approved common.Address - TokenId *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. -// -// Solidity: event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) -func (_POAPContract *POAPContractFilterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, approved []common.Address, tokenId []*big.Int) (*POAPContractApprovalIterator, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - var approvedRule []interface{} - for _, approvedItem := range approved { - approvedRule = append(approvedRule, approvedItem) - } - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _POAPContract.contract.FilterLogs(opts, "Approval", ownerRule, approvedRule, tokenIdRule) - if err != nil { - return nil, err - } - return &POAPContractApprovalIterator{contract: _POAPContract.contract, event: "Approval", logs: logs, sub: sub}, nil -} - -// WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. -// -// Solidity: event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) -func (_POAPContract *POAPContractFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *POAPContractApproval, owner []common.Address, approved []common.Address, tokenId []*big.Int) (event.Subscription, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - var approvedRule []interface{} - for _, approvedItem := range approved { - approvedRule = append(approvedRule, approvedItem) - } - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _POAPContract.contract.WatchLogs(opts, "Approval", ownerRule, approvedRule, tokenIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(POAPContractApproval) - if err := _POAPContract.contract.UnpackLog(event, "Approval", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. -// -// Solidity: event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) -func (_POAPContract *POAPContractFilterer) ParseApproval(log types.Log) (*POAPContractApproval, error) { - event := new(POAPContractApproval) - if err := _POAPContract.contract.UnpackLog(event, "Approval", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// POAPContractApprovalForAllIterator is returned from FilterApprovalForAll and is used to iterate over the raw logs and unpacked data for ApprovalForAll events raised by the POAPContract contract. -type POAPContractApprovalForAllIterator struct { - Event *POAPContractApprovalForAll // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *POAPContractApprovalForAllIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(POAPContractApprovalForAll) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(POAPContractApprovalForAll) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *POAPContractApprovalForAllIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *POAPContractApprovalForAllIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// POAPContractApprovalForAll represents a ApprovalForAll event raised by the POAPContract contract. -type POAPContractApprovalForAll struct { - Owner common.Address - Operator common.Address - Approved bool - Raw types.Log // Blockchain specific contextual infos -} - -// FilterApprovalForAll is a free log retrieval operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. -// -// Solidity: event ApprovalForAll(address indexed owner, address indexed operator, bool approved) -func (_POAPContract *POAPContractFilterer) FilterApprovalForAll(opts *bind.FilterOpts, owner []common.Address, operator []common.Address) (*POAPContractApprovalForAllIterator, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - var operatorRule []interface{} - for _, operatorItem := range operator { - operatorRule = append(operatorRule, operatorItem) - } - - logs, sub, err := _POAPContract.contract.FilterLogs(opts, "ApprovalForAll", ownerRule, operatorRule) - if err != nil { - return nil, err - } - return &POAPContractApprovalForAllIterator{contract: _POAPContract.contract, event: "ApprovalForAll", logs: logs, sub: sub}, nil -} - -// WatchApprovalForAll is a free log subscription operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. -// -// Solidity: event ApprovalForAll(address indexed owner, address indexed operator, bool approved) -func (_POAPContract *POAPContractFilterer) WatchApprovalForAll(opts *bind.WatchOpts, sink chan<- *POAPContractApprovalForAll, owner []common.Address, operator []common.Address) (event.Subscription, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - var operatorRule []interface{} - for _, operatorItem := range operator { - operatorRule = append(operatorRule, operatorItem) - } - - logs, sub, err := _POAPContract.contract.WatchLogs(opts, "ApprovalForAll", ownerRule, operatorRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(POAPContractApprovalForAll) - if err := _POAPContract.contract.UnpackLog(event, "ApprovalForAll", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseApprovalForAll is a log parse operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. -// -// Solidity: event ApprovalForAll(address indexed owner, address indexed operator, bool approved) -func (_POAPContract *POAPContractFilterer) ParseApprovalForAll(log types.Log) (*POAPContractApprovalForAll, error) { - event := new(POAPContractApprovalForAll) - if err := _POAPContract.contract.UnpackLog(event, "ApprovalForAll", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// POAPContractEventMinterAddedIterator is returned from FilterEventMinterAdded and is used to iterate over the raw logs and unpacked data for EventMinterAdded events raised by the POAPContract contract. -type POAPContractEventMinterAddedIterator struct { - Event *POAPContractEventMinterAdded // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *POAPContractEventMinterAddedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(POAPContractEventMinterAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(POAPContractEventMinterAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *POAPContractEventMinterAddedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *POAPContractEventMinterAddedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// POAPContractEventMinterAdded represents a EventMinterAdded event raised by the POAPContract contract. -type POAPContractEventMinterAdded struct { - EventId *big.Int - Account common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterEventMinterAdded is a free log retrieval operation binding the contract event 0xe1bd660d9f7c60e6fb12dd6479fdde12d21fc96385dc7b9b022c0b2f319e7391. -// -// Solidity: event EventMinterAdded(uint256 indexed eventId, address indexed account) -func (_POAPContract *POAPContractFilterer) FilterEventMinterAdded(opts *bind.FilterOpts, eventId []*big.Int, account []common.Address) (*POAPContractEventMinterAddedIterator, error) { - - var eventIdRule []interface{} - for _, eventIdItem := range eventId { - eventIdRule = append(eventIdRule, eventIdItem) - } - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - - logs, sub, err := _POAPContract.contract.FilterLogs(opts, "EventMinterAdded", eventIdRule, accountRule) - if err != nil { - return nil, err - } - return &POAPContractEventMinterAddedIterator{contract: _POAPContract.contract, event: "EventMinterAdded", logs: logs, sub: sub}, nil -} - -// WatchEventMinterAdded is a free log subscription operation binding the contract event 0xe1bd660d9f7c60e6fb12dd6479fdde12d21fc96385dc7b9b022c0b2f319e7391. -// -// Solidity: event EventMinterAdded(uint256 indexed eventId, address indexed account) -func (_POAPContract *POAPContractFilterer) WatchEventMinterAdded(opts *bind.WatchOpts, sink chan<- *POAPContractEventMinterAdded, eventId []*big.Int, account []common.Address) (event.Subscription, error) { - - var eventIdRule []interface{} - for _, eventIdItem := range eventId { - eventIdRule = append(eventIdRule, eventIdItem) - } - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - - logs, sub, err := _POAPContract.contract.WatchLogs(opts, "EventMinterAdded", eventIdRule, accountRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(POAPContractEventMinterAdded) - if err := _POAPContract.contract.UnpackLog(event, "EventMinterAdded", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseEventMinterAdded is a log parse operation binding the contract event 0xe1bd660d9f7c60e6fb12dd6479fdde12d21fc96385dc7b9b022c0b2f319e7391. -// -// Solidity: event EventMinterAdded(uint256 indexed eventId, address indexed account) -func (_POAPContract *POAPContractFilterer) ParseEventMinterAdded(log types.Log) (*POAPContractEventMinterAdded, error) { - event := new(POAPContractEventMinterAdded) - if err := _POAPContract.contract.UnpackLog(event, "EventMinterAdded", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// POAPContractEventMinterRemovedIterator is returned from FilterEventMinterRemoved and is used to iterate over the raw logs and unpacked data for EventMinterRemoved events raised by the POAPContract contract. -type POAPContractEventMinterRemovedIterator struct { - Event *POAPContractEventMinterRemoved // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *POAPContractEventMinterRemovedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(POAPContractEventMinterRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(POAPContractEventMinterRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *POAPContractEventMinterRemovedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *POAPContractEventMinterRemovedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// POAPContractEventMinterRemoved represents a EventMinterRemoved event raised by the POAPContract contract. -type POAPContractEventMinterRemoved struct { - EventId *big.Int - Account common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterEventMinterRemoved is a free log retrieval operation binding the contract event 0xb6882c4d609d560f6d57e78e73dd96027f0d9852739b0b922537a6dd3c8e944c. -// -// Solidity: event EventMinterRemoved(uint256 indexed eventId, address indexed account) -func (_POAPContract *POAPContractFilterer) FilterEventMinterRemoved(opts *bind.FilterOpts, eventId []*big.Int, account []common.Address) (*POAPContractEventMinterRemovedIterator, error) { - - var eventIdRule []interface{} - for _, eventIdItem := range eventId { - eventIdRule = append(eventIdRule, eventIdItem) - } - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - - logs, sub, err := _POAPContract.contract.FilterLogs(opts, "EventMinterRemoved", eventIdRule, accountRule) - if err != nil { - return nil, err - } - return &POAPContractEventMinterRemovedIterator{contract: _POAPContract.contract, event: "EventMinterRemoved", logs: logs, sub: sub}, nil -} - -// WatchEventMinterRemoved is a free log subscription operation binding the contract event 0xb6882c4d609d560f6d57e78e73dd96027f0d9852739b0b922537a6dd3c8e944c. -// -// Solidity: event EventMinterRemoved(uint256 indexed eventId, address indexed account) -func (_POAPContract *POAPContractFilterer) WatchEventMinterRemoved(opts *bind.WatchOpts, sink chan<- *POAPContractEventMinterRemoved, eventId []*big.Int, account []common.Address) (event.Subscription, error) { - - var eventIdRule []interface{} - for _, eventIdItem := range eventId { - eventIdRule = append(eventIdRule, eventIdItem) - } - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - - logs, sub, err := _POAPContract.contract.WatchLogs(opts, "EventMinterRemoved", eventIdRule, accountRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(POAPContractEventMinterRemoved) - if err := _POAPContract.contract.UnpackLog(event, "EventMinterRemoved", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseEventMinterRemoved is a log parse operation binding the contract event 0xb6882c4d609d560f6d57e78e73dd96027f0d9852739b0b922537a6dd3c8e944c. -// -// Solidity: event EventMinterRemoved(uint256 indexed eventId, address indexed account) -func (_POAPContract *POAPContractFilterer) ParseEventMinterRemoved(log types.Log) (*POAPContractEventMinterRemoved, error) { - event := new(POAPContractEventMinterRemoved) - if err := _POAPContract.contract.UnpackLog(event, "EventMinterRemoved", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// POAPContractEventTokenIterator is returned from FilterEventToken and is used to iterate over the raw logs and unpacked data for EventToken events raised by the POAPContract contract. -type POAPContractEventTokenIterator struct { - Event *POAPContractEventToken // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *POAPContractEventTokenIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(POAPContractEventToken) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(POAPContractEventToken) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *POAPContractEventTokenIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *POAPContractEventTokenIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// POAPContractEventToken represents a EventToken event raised by the POAPContract contract. -type POAPContractEventToken struct { - EventId *big.Int - TokenId *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterEventToken is a free log retrieval operation binding the contract event 0x4b3711cd7ece062b0828c1b6e08d814a72d4c003383a016c833cbb1b45956e34. -// -// Solidity: event EventToken(uint256 indexed eventId, uint256 tokenId) -func (_POAPContract *POAPContractFilterer) FilterEventToken(opts *bind.FilterOpts, eventId []*big.Int) (*POAPContractEventTokenIterator, error) { - - var eventIdRule []interface{} - for _, eventIdItem := range eventId { - eventIdRule = append(eventIdRule, eventIdItem) - } - - logs, sub, err := _POAPContract.contract.FilterLogs(opts, "EventToken", eventIdRule) - if err != nil { - return nil, err - } - return &POAPContractEventTokenIterator{contract: _POAPContract.contract, event: "EventToken", logs: logs, sub: sub}, nil -} - -// WatchEventToken is a free log subscription operation binding the contract event 0x4b3711cd7ece062b0828c1b6e08d814a72d4c003383a016c833cbb1b45956e34. -// -// Solidity: event EventToken(uint256 indexed eventId, uint256 tokenId) -func (_POAPContract *POAPContractFilterer) WatchEventToken(opts *bind.WatchOpts, sink chan<- *POAPContractEventToken, eventId []*big.Int) (event.Subscription, error) { - - var eventIdRule []interface{} - for _, eventIdItem := range eventId { - eventIdRule = append(eventIdRule, eventIdItem) - } - - logs, sub, err := _POAPContract.contract.WatchLogs(opts, "EventToken", eventIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(POAPContractEventToken) - if err := _POAPContract.contract.UnpackLog(event, "EventToken", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseEventToken is a log parse operation binding the contract event 0x4b3711cd7ece062b0828c1b6e08d814a72d4c003383a016c833cbb1b45956e34. -// -// Solidity: event EventToken(uint256 indexed eventId, uint256 tokenId) -func (_POAPContract *POAPContractFilterer) ParseEventToken(log types.Log) (*POAPContractEventToken, error) { - event := new(POAPContractEventToken) - if err := _POAPContract.contract.UnpackLog(event, "EventToken", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// POAPContractFrozenIterator is returned from FilterFrozen and is used to iterate over the raw logs and unpacked data for Frozen events raised by the POAPContract contract. -type POAPContractFrozenIterator struct { - Event *POAPContractFrozen // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *POAPContractFrozenIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(POAPContractFrozen) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(POAPContractFrozen) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *POAPContractFrozenIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *POAPContractFrozenIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// POAPContractFrozen represents a Frozen event raised by the POAPContract contract. -type POAPContractFrozen struct { - Id *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterFrozen is a free log retrieval operation binding the contract event 0x4d69b51fee53c28bd8b61fe008151577ca65160b5248f6225e74d64fd4cf7328. -// -// Solidity: event Frozen(uint256 id) -func (_POAPContract *POAPContractFilterer) FilterFrozen(opts *bind.FilterOpts) (*POAPContractFrozenIterator, error) { - - logs, sub, err := _POAPContract.contract.FilterLogs(opts, "Frozen") - if err != nil { - return nil, err - } - return &POAPContractFrozenIterator{contract: _POAPContract.contract, event: "Frozen", logs: logs, sub: sub}, nil -} - -// WatchFrozen is a free log subscription operation binding the contract event 0x4d69b51fee53c28bd8b61fe008151577ca65160b5248f6225e74d64fd4cf7328. -// -// Solidity: event Frozen(uint256 id) -func (_POAPContract *POAPContractFilterer) WatchFrozen(opts *bind.WatchOpts, sink chan<- *POAPContractFrozen) (event.Subscription, error) { - - logs, sub, err := _POAPContract.contract.WatchLogs(opts, "Frozen") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(POAPContractFrozen) - if err := _POAPContract.contract.UnpackLog(event, "Frozen", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseFrozen is a log parse operation binding the contract event 0x4d69b51fee53c28bd8b61fe008151577ca65160b5248f6225e74d64fd4cf7328. -// -// Solidity: event Frozen(uint256 id) -func (_POAPContract *POAPContractFilterer) ParseFrozen(log types.Log) (*POAPContractFrozen, error) { - event := new(POAPContractFrozen) - if err := _POAPContract.contract.UnpackLog(event, "Frozen", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// POAPContractPausedIterator is returned from FilterPaused and is used to iterate over the raw logs and unpacked data for Paused events raised by the POAPContract contract. -type POAPContractPausedIterator struct { - Event *POAPContractPaused // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *POAPContractPausedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(POAPContractPaused) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(POAPContractPaused) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *POAPContractPausedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *POAPContractPausedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// POAPContractPaused represents a Paused event raised by the POAPContract contract. -type POAPContractPaused struct { - Account common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterPaused is a free log retrieval operation binding the contract event 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258. -// -// Solidity: event Paused(address account) -func (_POAPContract *POAPContractFilterer) FilterPaused(opts *bind.FilterOpts) (*POAPContractPausedIterator, error) { - - logs, sub, err := _POAPContract.contract.FilterLogs(opts, "Paused") - if err != nil { - return nil, err - } - return &POAPContractPausedIterator{contract: _POAPContract.contract, event: "Paused", logs: logs, sub: sub}, nil -} - -// WatchPaused is a free log subscription operation binding the contract event 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258. -// -// Solidity: event Paused(address account) -func (_POAPContract *POAPContractFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *POAPContractPaused) (event.Subscription, error) { - - logs, sub, err := _POAPContract.contract.WatchLogs(opts, "Paused") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(POAPContractPaused) - if err := _POAPContract.contract.UnpackLog(event, "Paused", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParsePaused is a log parse operation binding the contract event 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258. -// -// Solidity: event Paused(address account) -func (_POAPContract *POAPContractFilterer) ParsePaused(log types.Log) (*POAPContractPaused, error) { - event := new(POAPContractPaused) - if err := _POAPContract.contract.UnpackLog(event, "Paused", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// POAPContractTransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the POAPContract contract. -type POAPContractTransferIterator struct { - Event *POAPContractTransfer // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *POAPContractTransferIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(POAPContractTransfer) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(POAPContractTransfer) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *POAPContractTransferIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *POAPContractTransferIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// POAPContractTransfer represents a Transfer event raised by the POAPContract contract. -type POAPContractTransfer struct { - From common.Address - To common.Address - TokenId *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. -// -// Solidity: event Transfer(address indexed from, address indexed to, uint256 indexed tokenId) -func (_POAPContract *POAPContractFilterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address, tokenId []*big.Int) (*POAPContractTransferIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _POAPContract.contract.FilterLogs(opts, "Transfer", fromRule, toRule, tokenIdRule) - if err != nil { - return nil, err - } - return &POAPContractTransferIterator{contract: _POAPContract.contract, event: "Transfer", logs: logs, sub: sub}, nil -} - -// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. -// -// Solidity: event Transfer(address indexed from, address indexed to, uint256 indexed tokenId) -func (_POAPContract *POAPContractFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *POAPContractTransfer, from []common.Address, to []common.Address, tokenId []*big.Int) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _POAPContract.contract.WatchLogs(opts, "Transfer", fromRule, toRule, tokenIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(POAPContractTransfer) - if err := _POAPContract.contract.UnpackLog(event, "Transfer", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. -// -// Solidity: event Transfer(address indexed from, address indexed to, uint256 indexed tokenId) -func (_POAPContract *POAPContractFilterer) ParseTransfer(log types.Log) (*POAPContractTransfer, error) { - event := new(POAPContractTransfer) - if err := _POAPContract.contract.UnpackLog(event, "Transfer", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// POAPContractUnfrozenIterator is returned from FilterUnfrozen and is used to iterate over the raw logs and unpacked data for Unfrozen events raised by the POAPContract contract. -type POAPContractUnfrozenIterator struct { - Event *POAPContractUnfrozen // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *POAPContractUnfrozenIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(POAPContractUnfrozen) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(POAPContractUnfrozen) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *POAPContractUnfrozenIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *POAPContractUnfrozenIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// POAPContractUnfrozen represents a Unfrozen event raised by the POAPContract contract. -type POAPContractUnfrozen struct { - Id *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterUnfrozen is a free log retrieval operation binding the contract event 0x083eea12772ab70fba01c8212d02f3bc5dc29b8540dcdc84298e5dfa22731b92. -// -// Solidity: event Unfrozen(uint256 id) -func (_POAPContract *POAPContractFilterer) FilterUnfrozen(opts *bind.FilterOpts) (*POAPContractUnfrozenIterator, error) { - - logs, sub, err := _POAPContract.contract.FilterLogs(opts, "Unfrozen") - if err != nil { - return nil, err - } - return &POAPContractUnfrozenIterator{contract: _POAPContract.contract, event: "Unfrozen", logs: logs, sub: sub}, nil -} - -// WatchUnfrozen is a free log subscription operation binding the contract event 0x083eea12772ab70fba01c8212d02f3bc5dc29b8540dcdc84298e5dfa22731b92. -// -// Solidity: event Unfrozen(uint256 id) -func (_POAPContract *POAPContractFilterer) WatchUnfrozen(opts *bind.WatchOpts, sink chan<- *POAPContractUnfrozen) (event.Subscription, error) { - - logs, sub, err := _POAPContract.contract.WatchLogs(opts, "Unfrozen") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(POAPContractUnfrozen) - if err := _POAPContract.contract.UnpackLog(event, "Unfrozen", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseUnfrozen is a log parse operation binding the contract event 0x083eea12772ab70fba01c8212d02f3bc5dc29b8540dcdc84298e5dfa22731b92. -// -// Solidity: event Unfrozen(uint256 id) -func (_POAPContract *POAPContractFilterer) ParseUnfrozen(log types.Log) (*POAPContractUnfrozen, error) { - event := new(POAPContractUnfrozen) - if err := _POAPContract.contract.UnpackLog(event, "Unfrozen", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// POAPContractUnpausedIterator is returned from FilterUnpaused and is used to iterate over the raw logs and unpacked data for Unpaused events raised by the POAPContract contract. -type POAPContractUnpausedIterator struct { - Event *POAPContractUnpaused // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *POAPContractUnpausedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(POAPContractUnpaused) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(POAPContractUnpaused) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *POAPContractUnpausedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *POAPContractUnpausedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// POAPContractUnpaused represents a Unpaused event raised by the POAPContract contract. -type POAPContractUnpaused struct { - Account common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterUnpaused is a free log retrieval operation binding the contract event 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa. -// -// Solidity: event Unpaused(address account) -func (_POAPContract *POAPContractFilterer) FilterUnpaused(opts *bind.FilterOpts) (*POAPContractUnpausedIterator, error) { - - logs, sub, err := _POAPContract.contract.FilterLogs(opts, "Unpaused") - if err != nil { - return nil, err - } - return &POAPContractUnpausedIterator{contract: _POAPContract.contract, event: "Unpaused", logs: logs, sub: sub}, nil -} - -// WatchUnpaused is a free log subscription operation binding the contract event 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa. -// -// Solidity: event Unpaused(address account) -func (_POAPContract *POAPContractFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *POAPContractUnpaused) (event.Subscription, error) { - - logs, sub, err := _POAPContract.contract.WatchLogs(opts, "Unpaused") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(POAPContractUnpaused) - if err := _POAPContract.contract.UnpackLog(event, "Unpaused", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseUnpaused is a log parse operation binding the contract event 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa. -// -// Solidity: event Unpaused(address account) -func (_POAPContract *POAPContractFilterer) ParseUnpaused(log types.Log) (*POAPContractUnpaused, error) { - event := new(POAPContractUnpaused) - if err := _POAPContract.contract.UnpackLog(event, "Unpaused", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/lexer/consts.go b/internal/lexer/consts.go similarity index 100% rename from lexer/consts.go rename to internal/lexer/consts.go diff --git a/lexer/eval.go b/internal/lexer/eval.go similarity index 100% rename from lexer/eval.go rename to internal/lexer/eval.go diff --git a/lexer/eval_test.go b/internal/lexer/eval_test.go similarity index 100% rename from lexer/eval_test.go rename to internal/lexer/eval_test.go diff --git a/lexer/example_test.go b/internal/lexer/example_test.go similarity index 100% rename from lexer/example_test.go rename to internal/lexer/example_test.go diff --git a/lexer/lexer.go b/internal/lexer/lexer.go similarity index 100% rename from lexer/lexer.go rename to internal/lexer/lexer.go diff --git a/lexer/lexer_test.go b/internal/lexer/lexer_test.go similarity index 100% rename from lexer/lexer_test.go rename to internal/lexer/lexer_test.go diff --git a/lexer/token.go b/internal/lexer/token.go similarity index 100% rename from lexer/token.go rename to internal/lexer/token.go diff --git a/lexer/token_test.go b/internal/lexer/token_test.go similarity index 100% rename from lexer/token_test.go rename to internal/lexer/token_test.go diff --git a/queue/queue.go b/internal/queue/queue.go similarity index 100% rename from queue/queue.go rename to internal/queue/queue.go diff --git a/queue/queue_test.go b/internal/queue/queue_test.go similarity index 100% rename from queue/queue_test.go rename to internal/queue/queue_test.go diff --git a/roundedcensus/roundedcensus.go b/internal/roundedcensus/roundedcensus.go similarity index 100% rename from roundedcensus/roundedcensus.go rename to internal/roundedcensus/roundedcensus.go diff --git a/roundedcensus/roundedcensus_test.go b/internal/roundedcensus/roundedcensus_test.go similarity index 100% rename from roundedcensus/roundedcensus_test.go rename to internal/roundedcensus/roundedcensus_test.go diff --git a/strategyoperators/combinators.go b/internal/strategyoperators/combinators.go similarity index 100% rename from strategyoperators/combinators.go rename to internal/strategyoperators/combinators.go diff --git a/strategyoperators/combinators_test.go b/internal/strategyoperators/combinators_test.go similarity index 100% rename from strategyoperators/combinators_test.go rename to internal/strategyoperators/combinators_test.go diff --git a/strategyoperators/operators.go b/internal/strategyoperators/operators.go similarity index 99% rename from strategyoperators/operators.go rename to internal/strategyoperators/operators.go index 0ef8d4a4..a5bb330d 100644 --- a/strategyoperators/operators.go +++ b/internal/strategyoperators/operators.go @@ -8,7 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" queries "github.com/vocdoni/census3/db/sqlc" - "github.com/vocdoni/census3/lexer" + "github.com/vocdoni/census3/internal/lexer" ) // AND method returns a AND operator function that can be used in a strategy diff --git a/strategyoperators/operators_test.go b/internal/strategyoperators/operators_test.go similarity index 99% rename from strategyoperators/operators_test.go rename to internal/strategyoperators/operators_test.go index bdecefed..d41d1d20 100644 --- a/strategyoperators/operators_test.go +++ b/internal/strategyoperators/operators_test.go @@ -8,7 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" qt "github.com/frankban/quicktest" - "github.com/vocdoni/census3/lexer" + "github.com/vocdoni/census3/internal/lexer" ) func Test_basicOperators(t *testing.T) { diff --git a/strategyoperators/strategyoperators.go b/internal/strategyoperators/strategyoperators.go similarity index 99% rename from strategyoperators/strategyoperators.go rename to internal/strategyoperators/strategyoperators.go index cb060cc5..1948e12e 100644 --- a/strategyoperators/strategyoperators.go +++ b/internal/strategyoperators/strategyoperators.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/common" queries "github.com/vocdoni/census3/db/sqlc" - "github.com/vocdoni/census3/lexer" + "github.com/vocdoni/census3/internal/lexer" ) const ( diff --git a/strategyoperators/strategyoperators_test.go b/internal/strategyoperators/strategyoperators_test.go similarity index 100% rename from strategyoperators/strategyoperators_test.go rename to internal/strategyoperators/strategyoperators_test.go From 1f1bb1b90c4b6ff087a967f3b52b493c1700ec3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Fri, 26 Jan 2024 17:00:35 +0100 Subject: [PATCH 16/35] modify current token types indexes to the new ones in the database migration --- db/migrations/0003_census3.sql | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/db/migrations/0003_census3.sql b/db/migrations/0003_census3.sql index 596cb932..163d03d9 100644 --- a/db/migrations/0003_census3.sql +++ b/db/migrations/0003_census3.sql @@ -2,15 +2,36 @@ -- +goose Up DELETE FROM token_types; UPDATE sqlite_sequence SET seq = 0 WHERE name = 'token_types'; -INSERT INTO token_types (type_name) VALUES ('erc20'); -INSERT INTO token_types (type_name) VALUES ('erc721');; -INSERT INTO token_types (type_name) VALUES ('erc777'); -INSERT INTO token_types (type_name) VALUES ('poap'); +INSERT INTO token_types (id, type_name) VALUES (0, 'unknown'); +INSERT INTO token_types (id, type_name) VALUES (1, 'erc20'); +INSERT INTO token_types (id, type_name) VALUES (2, 'erc721');; +INSERT INTO token_types (id, type_name) VALUES (3, 'erc777'); +INSERT INTO token_types (id, type_name) VALUES (4, 'poap'); +INSERT INTO token_types (id, type_name) VALUES (5, 'gitcoinpassport'); + +DELETE FROM tokens WHERE type_id = 3; +DELETE FROM tokens WHERE type_id = 5; +DELETE FROM tokens WHERE type_id = 6; + +UPDATE tokens SET type_id = 3 WHERE type_id = 4; +UPDATE tokens SET type_id = 4 WHERE type_id = 8; +UPDATE tokens SET type_id = 5 WHERE type_id = 100; ALTER TABLE tokens ADD COLUMN last_block BIGINT NOT NULL DEFAULT 0; ALTER TABLE tokens ADD COLUMN analysed_transfers BIGINT NOT NULL DEFAULT 0; -- List of changes: -- * Remove all token types and reset sequence +-- * Recreate token types with new ids: +-- * [new] unknown 0 +-- * erc20 1 +-- * erc721 2 +-- * [updated] erc777 from 4 to 3 +-- * [updated] poap from 8 to 4 +-- * [updated] gitcoinpassport from 100 to 5 +-- * [removed] erc1155 +-- * [removed] nation3 +-- * [removed] want +-- * [removed] erc721_burned -- * Add 'last_block' column to 'tokens' table -- * Add 'analysed_transfers' column to 'tokens' table \ No newline at end of file From 307ed678b6b9a3c9fe6c540dabe8bf192511c7e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Fri, 26 Jan 2024 17:51:46 +0100 Subject: [PATCH 17/35] holder queries cleaned --- api/holders.go | 8 +- api/tokens.go | 11 +- db/queries/holders.sql | 62 +-- db/sqlc/holders.sql.go | 383 ++++-------------- .../strategyoperators_test.go | 5 - scanner/scanner.go | 23 +- 6 files changed, 102 insertions(+), 390 deletions(-) diff --git a/api/holders.go b/api/holders.go index b062f5e1..3f943a96 100644 --- a/api/holders.go +++ b/api/holders.go @@ -96,8 +96,8 @@ func (capi *census3API) listHoldersAtLastBlock(address common.Address, return nil, 0, ErrCantGetToken.WithErr(err) } // get token holders count - holders, err := capi.db.QueriesRO.TokenHoldersByTokenIDAndChainIDAndExternalID(internalCtx, - queries.TokenHoldersByTokenIDAndChainIDAndExternalIDParams{ + holders, err := capi.db.QueriesRO.ListTokenHolders(internalCtx, + queries.ListTokenHoldersParams{ TokenID: address.Bytes(), ChainID: chainID, ExternalID: externalID, @@ -129,10 +129,10 @@ func (capi *census3API) listHoldersAtLastBlock(address common.Address, balances := make(map[string]string) for i, holder := range holders { log.Infow("getting balance", - "holder", common.BytesToAddress(holder.ID).String(), + "holder", common.BytesToAddress(holder.HolderID).String(), "token", address.String(), "progress", fmt.Sprintf("%d/%d", i+1, len(holders))) - holderAddress := common.BytesToAddress(holder.ID) + holderAddress := common.BytesToAddress(holder.HolderID) balance, err := provider.BalanceAt(internalCtx, holderAddress, nil, lastBlockNumber) if err != nil { return nil, lastBlockNumber, ErrCantGetTokenHolders.WithErr(err) diff --git a/api/tokens.go b/api/tokens.go index 488614e7..ee0b8b2e 100644 --- a/api/tokens.go +++ b/api/tokens.go @@ -373,12 +373,11 @@ func (capi *census3API) deleteToken(msg *api.APIdata, ctx *httprouter.HTTPContex return ErrNotFoundToken.WithErr(err) } // delete the token holders - if _, err := qtx.DeleteTokenHoldersByTokenIDAndChainIDAndExternalID(internalCtx, - queries.DeleteTokenHoldersByTokenIDAndChainIDAndExternalIDParams{ - TokenID: address.Bytes(), - ChainID: uint64(chainID), - ExternalID: externalID, - }); err != nil { + if _, err := qtx.DeleteTokenHolder(internalCtx, queries.DeleteTokenHolderParams{ + TokenID: address.Bytes(), + ChainID: uint64(chainID), + ExternalID: externalID, + }); err != nil { return ErrCantDeleteToken.WithErr(err) } // delete strategies tokens diff --git a/db/queries/holders.sql b/db/queries/holders.sql index d8aa1e81..94abbbad 100644 --- a/db/queries/holders.sql +++ b/db/queries/holders.sql @@ -1,40 +1,10 @@ --- name: CreateHolder :execresult -INSERT INTO holders (id) -VALUES (?); --- name: TokensByHolderID :many -SELECT tokens.* -FROM tokens -JOIN token_holders ON tokens.id = token_holders.token_id -WHERE token_holders.holder_id = ?; - --- name: TokenHoldersByTokenID :many -SELECT holders.*, token_holders.balance -FROM holders -JOIN token_holders ON holders.id = token_holders.holder_id -WHERE token_holders.token_id = ?; - --- name: TokenHoldersByTokenIDAndExternalID :many -SELECT holders.*, token_holders.balance -FROM holders -JOIN token_holders ON holders.id = token_holders.holder_id -WHERE token_holders.token_id = ? AND token_holders.external_id = ?; - --- name: TokenHoldersByTokenIDAndChainIDAndExternalID :many -SELECT holders.*, token_holders.balance -FROM holders -JOIN token_holders ON holders.id = token_holders.holder_id -WHERE token_holders.token_id = ? AND token_holders.chain_id = ? AND token_holders.external_id = ?; - --- name: TokenHolderByTokenIDAndHolderID :one -SELECT holders.*, token_holders.* -FROM holders -JOIN token_holders ON holders.id = token_holders.holder_id -WHERE token_holders.token_id = ? -AND token_holders.chain_id = ? -AND token_holders.holder_id = ?; +-- name: ListTokenHolders :many +SELECT * +FROM token_holders +WHERE token_id = ? AND chain_id = ? AND external_id = ?; --- name: TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID :one +-- name: GetTokenHolder :one SELECT * FROM token_holders WHERE token_id = ? @@ -42,12 +12,6 @@ WHERE token_id = ? AND chain_id = ? AND external_id = ?; --- name: TokenHolderByTokenIDAndBlockIDAndHolderID :one -SELECT holders.*, token_holders.balance -FROM holders -JOIN token_holders ON holders.id = token_holders.holder_id -WHERE token_holders.token_id = ? AND token_holders.holder_id = ? AND token_holders.block_id = ?; - -- name: ExistTokenHolder :one SELECT EXISTS ( SELECT holder_id @@ -58,13 +22,6 @@ SELECT EXISTS ( AND external_id = ? ); --- name: LastBlockByTokenID :one -SELECT block_id -FROM token_holders -WHERE token_id = ? -ORDER BY block_id DESC -LIMIT 1; - -- name: CountTokenHolders :one SELECT COUNT(holder_id) FROM token_holders @@ -96,13 +53,6 @@ WHERE token_id = sqlc.arg(token_id) AND chain_id = sqlc.arg(chain_id) AND external_id = sqlc.arg(external_id); --- name: DeleteTokenHolder :execresult -DELETE FROM token_holders -WHERE token_id = sqlc.arg(token_id) - AND holder_id = sqlc.arg(holder_id) - AND chain_id = sqlc.arg(chain_id) - AND external_id = sqlc.arg(external_id); - -- name: TokenHoldersByTokenIDAndChainIDAndMinBalance :many SELECT token_holders.holder_id, token_holders.balance FROM token_holders @@ -111,7 +61,7 @@ WHERE token_holders.token_id = ? AND token_holders.external_id = ? AND token_holders.balance >= ?; --- name: DeleteTokenHoldersByTokenIDAndChainIDAndExternalID :execresult +-- name: DeleteTokenHolder :execresult DELETE FROM token_holders WHERE token_id = ? AND chain_id = ? AND external_id = ?; -- name: TokenHoldersByStrategyID :many diff --git a/db/sqlc/holders.sql.go b/db/sqlc/holders.sql.go index aa387aca..1683b396 100644 --- a/db/sqlc/holders.sql.go +++ b/db/sqlc/holders.sql.go @@ -111,15 +111,6 @@ func (q *Queries) CountTokenHolders(ctx context.Context, arg CountTokenHoldersPa return count, err } -const createHolder = `-- name: CreateHolder :execresult -INSERT INTO holders (id) -VALUES (?) -` - -func (q *Queries) CreateHolder(ctx context.Context, id annotations.Address) (sql.Result, error) { - return q.db.ExecContext(ctx, createHolder, id) -} - const createTokenHolder = `-- name: CreateTokenHolder :execresult INSERT INTO token_holders ( token_id, @@ -155,41 +146,17 @@ func (q *Queries) CreateTokenHolder(ctx context.Context, arg CreateTokenHolderPa } const deleteTokenHolder = `-- name: DeleteTokenHolder :execresult -DELETE FROM token_holders -WHERE token_id = ? - AND holder_id = ? - AND chain_id = ? - AND external_id = ? +DELETE FROM token_holders WHERE token_id = ? AND chain_id = ? AND external_id = ? ` type DeleteTokenHolderParams struct { TokenID annotations.Address - HolderID annotations.Address ChainID uint64 ExternalID string } func (q *Queries) DeleteTokenHolder(ctx context.Context, arg DeleteTokenHolderParams) (sql.Result, error) { - return q.db.ExecContext(ctx, deleteTokenHolder, - arg.TokenID, - arg.HolderID, - arg.ChainID, - arg.ExternalID, - ) -} - -const deleteTokenHoldersByTokenIDAndChainIDAndExternalID = `-- name: DeleteTokenHoldersByTokenIDAndChainIDAndExternalID :execresult -DELETE FROM token_holders WHERE token_id = ? AND chain_id = ? AND external_id = ? -` - -type DeleteTokenHoldersByTokenIDAndChainIDAndExternalIDParams struct { - TokenID annotations.Address - ChainID uint64 - ExternalID string -} - -func (q *Queries) DeleteTokenHoldersByTokenIDAndChainIDAndExternalID(ctx context.Context, arg DeleteTokenHoldersByTokenIDAndChainIDAndExternalIDParams) (sql.Result, error) { - return q.db.ExecContext(ctx, deleteTokenHoldersByTokenIDAndChainIDAndExternalID, arg.TokenID, arg.ChainID, arg.ExternalID) + return q.db.ExecContext(ctx, deleteTokenHolder, arg.TokenID, arg.ChainID, arg.ExternalID) } const existTokenHolder = `-- name: ExistTokenHolder :one @@ -222,19 +189,81 @@ func (q *Queries) ExistTokenHolder(ctx context.Context, arg ExistTokenHolderPara return exists, err } -const lastBlockByTokenID = `-- name: LastBlockByTokenID :one -SELECT block_id +const getTokenHolder = `-- name: GetTokenHolder :one +SELECT token_id, holder_id, balance, block_id, chain_id, external_id FROM token_holders -WHERE token_id = ? -ORDER BY block_id DESC -LIMIT 1 +WHERE token_id = ? + AND holder_id = ? + AND chain_id = ? + AND external_id = ? ` -func (q *Queries) LastBlockByTokenID(ctx context.Context, tokenID annotations.Address) (uint64, error) { - row := q.db.QueryRowContext(ctx, lastBlockByTokenID, tokenID) - var block_id uint64 - err := row.Scan(&block_id) - return block_id, err +type GetTokenHolderParams struct { + TokenID annotations.Address + HolderID annotations.Address + ChainID uint64 + ExternalID string +} + +func (q *Queries) GetTokenHolder(ctx context.Context, arg GetTokenHolderParams) (TokenHolder, error) { + row := q.db.QueryRowContext(ctx, getTokenHolder, + arg.TokenID, + arg.HolderID, + arg.ChainID, + arg.ExternalID, + ) + var i TokenHolder + err := row.Scan( + &i.TokenID, + &i.HolderID, + &i.Balance, + &i.BlockID, + &i.ChainID, + &i.ExternalID, + ) + return i, err +} + +const listTokenHolders = `-- name: ListTokenHolders :many +SELECT token_id, holder_id, balance, block_id, chain_id, external_id +FROM token_holders +WHERE token_id = ? AND chain_id = ? AND external_id = ? +` + +type ListTokenHoldersParams struct { + TokenID annotations.Address + ChainID uint64 + ExternalID string +} + +func (q *Queries) ListTokenHolders(ctx context.Context, arg ListTokenHoldersParams) ([]TokenHolder, error) { + rows, err := q.db.QueryContext(ctx, listTokenHolders, arg.TokenID, arg.ChainID, arg.ExternalID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TokenHolder + for rows.Next() { + var i TokenHolder + if err := rows.Scan( + &i.TokenID, + &i.HolderID, + &i.Balance, + &i.BlockID, + &i.ChainID, + &i.ExternalID, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil } const oROperator = `-- name: OROperator :many @@ -330,106 +359,6 @@ func (q *Queries) OROperator(ctx context.Context, arg OROperatorParams) ([]OROpe return items, nil } -const tokenHolderByTokenIDAndBlockIDAndHolderID = `-- name: TokenHolderByTokenIDAndBlockIDAndHolderID :one -SELECT holders.id, token_holders.balance -FROM holders -JOIN token_holders ON holders.id = token_holders.holder_id -WHERE token_holders.token_id = ? AND token_holders.holder_id = ? AND token_holders.block_id = ? -` - -type TokenHolderByTokenIDAndBlockIDAndHolderIDParams struct { - TokenID annotations.Address - HolderID annotations.Address - BlockID uint64 -} - -type TokenHolderByTokenIDAndBlockIDAndHolderIDRow struct { - ID annotations.Address - Balance string -} - -func (q *Queries) TokenHolderByTokenIDAndBlockIDAndHolderID(ctx context.Context, arg TokenHolderByTokenIDAndBlockIDAndHolderIDParams) (TokenHolderByTokenIDAndBlockIDAndHolderIDRow, error) { - row := q.db.QueryRowContext(ctx, tokenHolderByTokenIDAndBlockIDAndHolderID, arg.TokenID, arg.HolderID, arg.BlockID) - var i TokenHolderByTokenIDAndBlockIDAndHolderIDRow - err := row.Scan(&i.ID, &i.Balance) - return i, err -} - -const tokenHolderByTokenIDAndHolderID = `-- name: TokenHolderByTokenIDAndHolderID :one -SELECT holders.id, token_holders.token_id, token_holders.holder_id, token_holders.balance, token_holders.block_id, token_holders.chain_id, token_holders.external_id -FROM holders -JOIN token_holders ON holders.id = token_holders.holder_id -WHERE token_holders.token_id = ? -AND token_holders.chain_id = ? -AND token_holders.holder_id = ? -` - -type TokenHolderByTokenIDAndHolderIDParams struct { - TokenID annotations.Address - ChainID uint64 - HolderID annotations.Address -} - -type TokenHolderByTokenIDAndHolderIDRow struct { - ID annotations.Address - TokenID annotations.Address - HolderID annotations.Address - Balance string - BlockID uint64 - ChainID uint64 - ExternalID string -} - -func (q *Queries) TokenHolderByTokenIDAndHolderID(ctx context.Context, arg TokenHolderByTokenIDAndHolderIDParams) (TokenHolderByTokenIDAndHolderIDRow, error) { - row := q.db.QueryRowContext(ctx, tokenHolderByTokenIDAndHolderID, arg.TokenID, arg.ChainID, arg.HolderID) - var i TokenHolderByTokenIDAndHolderIDRow - err := row.Scan( - &i.ID, - &i.TokenID, - &i.HolderID, - &i.Balance, - &i.BlockID, - &i.ChainID, - &i.ExternalID, - ) - return i, err -} - -const tokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID = `-- name: TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID :one -SELECT token_id, holder_id, balance, block_id, chain_id, external_id -FROM token_holders -WHERE token_id = ? - AND holder_id = ? - AND chain_id = ? - AND external_id = ? -` - -type TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDParams struct { - TokenID annotations.Address - HolderID annotations.Address - ChainID uint64 - ExternalID string -} - -func (q *Queries) TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID(ctx context.Context, arg TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDParams) (TokenHolder, error) { - row := q.db.QueryRowContext(ctx, tokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID, - arg.TokenID, - arg.HolderID, - arg.ChainID, - arg.ExternalID, - ) - var i TokenHolder - err := row.Scan( - &i.TokenID, - &i.HolderID, - &i.Balance, - &i.BlockID, - &i.ChainID, - &i.ExternalID, - ) - return i, err -} - const tokenHoldersByStrategyID = `-- name: TokenHoldersByStrategyID :many SELECT token_holders.holder_id, token_holders.balance, strategy_tokens.min_balance FROM token_holders @@ -470,82 +399,6 @@ func (q *Queries) TokenHoldersByStrategyID(ctx context.Context, strategyID uint6 return items, nil } -const tokenHoldersByTokenID = `-- name: TokenHoldersByTokenID :many -SELECT holders.id, token_holders.balance -FROM holders -JOIN token_holders ON holders.id = token_holders.holder_id -WHERE token_holders.token_id = ? -` - -type TokenHoldersByTokenIDRow struct { - ID annotations.Address - Balance string -} - -func (q *Queries) TokenHoldersByTokenID(ctx context.Context, tokenID annotations.Address) ([]TokenHoldersByTokenIDRow, error) { - rows, err := q.db.QueryContext(ctx, tokenHoldersByTokenID, tokenID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []TokenHoldersByTokenIDRow - for rows.Next() { - var i TokenHoldersByTokenIDRow - if err := rows.Scan(&i.ID, &i.Balance); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const tokenHoldersByTokenIDAndChainIDAndExternalID = `-- name: TokenHoldersByTokenIDAndChainIDAndExternalID :many -SELECT holders.id, token_holders.balance -FROM holders -JOIN token_holders ON holders.id = token_holders.holder_id -WHERE token_holders.token_id = ? AND token_holders.chain_id = ? AND token_holders.external_id = ? -` - -type TokenHoldersByTokenIDAndChainIDAndExternalIDParams struct { - TokenID annotations.Address - ChainID uint64 - ExternalID string -} - -type TokenHoldersByTokenIDAndChainIDAndExternalIDRow struct { - ID annotations.Address - Balance string -} - -func (q *Queries) TokenHoldersByTokenIDAndChainIDAndExternalID(ctx context.Context, arg TokenHoldersByTokenIDAndChainIDAndExternalIDParams) ([]TokenHoldersByTokenIDAndChainIDAndExternalIDRow, error) { - rows, err := q.db.QueryContext(ctx, tokenHoldersByTokenIDAndChainIDAndExternalID, arg.TokenID, arg.ChainID, arg.ExternalID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []TokenHoldersByTokenIDAndChainIDAndExternalIDRow - for rows.Next() { - var i TokenHoldersByTokenIDAndChainIDAndExternalIDRow - if err := rows.Scan(&i.ID, &i.Balance); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - const tokenHoldersByTokenIDAndChainIDAndMinBalance = `-- name: TokenHoldersByTokenIDAndChainIDAndMinBalance :many SELECT token_holders.holder_id, token_holders.balance FROM token_holders @@ -595,94 +448,6 @@ func (q *Queries) TokenHoldersByTokenIDAndChainIDAndMinBalance(ctx context.Conte return items, nil } -const tokenHoldersByTokenIDAndExternalID = `-- name: TokenHoldersByTokenIDAndExternalID :many -SELECT holders.id, token_holders.balance -FROM holders -JOIN token_holders ON holders.id = token_holders.holder_id -WHERE token_holders.token_id = ? AND token_holders.external_id = ? -` - -type TokenHoldersByTokenIDAndExternalIDParams struct { - TokenID annotations.Address - ExternalID string -} - -type TokenHoldersByTokenIDAndExternalIDRow struct { - ID annotations.Address - Balance string -} - -func (q *Queries) TokenHoldersByTokenIDAndExternalID(ctx context.Context, arg TokenHoldersByTokenIDAndExternalIDParams) ([]TokenHoldersByTokenIDAndExternalIDRow, error) { - rows, err := q.db.QueryContext(ctx, tokenHoldersByTokenIDAndExternalID, arg.TokenID, arg.ExternalID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []TokenHoldersByTokenIDAndExternalIDRow - for rows.Next() { - var i TokenHoldersByTokenIDAndExternalIDRow - if err := rows.Scan(&i.ID, &i.Balance); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const tokensByHolderID = `-- name: TokensByHolderID :many -SELECT tokens.id, tokens.name, tokens.symbol, tokens.decimals, tokens.total_supply, tokens.creation_block, tokens.type_id, tokens.synced, tokens.tags, tokens.chain_id, tokens.chain_address, tokens.external_id, tokens.default_strategy, tokens.icon_uri, tokens.created_at, tokens.last_block, tokens.analysed_transfers -FROM tokens -JOIN token_holders ON tokens.id = token_holders.token_id -WHERE token_holders.holder_id = ? -` - -func (q *Queries) TokensByHolderID(ctx context.Context, holderID annotations.Address) ([]Token, error) { - rows, err := q.db.QueryContext(ctx, tokensByHolderID, holderID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []Token - for rows.Next() { - var i Token - if err := rows.Scan( - &i.ID, - &i.Name, - &i.Symbol, - &i.Decimals, - &i.TotalSupply, - &i.CreationBlock, - &i.TypeID, - &i.Synced, - &i.Tags, - &i.ChainID, - &i.ChainAddress, - &i.ExternalID, - &i.DefaultStrategy, - &i.IconUri, - &i.CreatedAt, - &i.LastBlock, - &i.AnalysedTransfers, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - const updateTokenHolderBalance = `-- name: UpdateTokenHolderBalance :execresult UPDATE token_holders SET balance = ?, diff --git a/internal/strategyoperators/strategyoperators_test.go b/internal/strategyoperators/strategyoperators_test.go index 0fb600a4..3d367e17 100644 --- a/internal/strategyoperators/strategyoperators_test.go +++ b/internal/strategyoperators/strategyoperators_test.go @@ -6,7 +6,6 @@ import ( "math/big" "os" "path/filepath" - "strings" "testing" "time" @@ -100,10 +99,6 @@ func mockedStrategyOperator(dataDir string) (*StrategyOperators, error) { }() qtx := database.QueriesRW.WithTx(tx) for _, m := range mockedTokenHolders { - _, err = qtx.CreateHolder(ctx, m.HolderID) - if err != nil && !strings.Contains(err.Error(), "UNIQUE constraint failed") { - return nil, err - } // if the token holder not exists, create it _, err = qtx.CreateTokenHolder(ctx, queries.CreateTokenHolderParams{ TokenID: m.TokenID, diff --git a/scanner/scanner.go b/scanner/scanner.go index 1c4bb229..7ffed7db 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -290,8 +290,8 @@ func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) ( } } // get the current token holders from the database - results, err := qtx.TokenHoldersByTokenIDAndChainIDAndExternalID(internalCtx, - queries.TokenHoldersByTokenIDAndChainIDAndExternalIDParams{ + results, err := qtx.ListTokenHolders(internalCtx, + queries.ListTokenHoldersParams{ TokenID: token.Address.Bytes(), ChainID: token.ChainID, ExternalID: token.ExternalID, @@ -301,7 +301,11 @@ func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) ( } currentHolders := map[common.Address]*big.Int{} for _, result := range results { - currentHolders[common.BytesToAddress(result.ID)] = big.NewInt(0).SetBytes([]byte(result.Balance)) + bBalance, ok := new(big.Int).SetString(result.Balance, 10) + if !ok { + return nil, 0, token.LastBlock, token.Synced, fmt.Errorf("error parsing token holder balance") + } + currentHolders[common.BytesToAddress(result.HolderID)] = bBalance } // close the database tx and commit it if err := tx.Commit(); err != nil { @@ -400,13 +404,12 @@ func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, created, updated, deleted := 0, 0, 0 for addr, balance := range holders { // get the current token holder from the database - currentTokenHolder, err := qtx.TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalID(ctx, - queries.TokenHolderByTokenIDAndHolderIDAndChainIDAndExternalIDParams{ - TokenID: token.Address.Bytes(), - ChainID: token.ChainID, - ExternalID: token.ExternalID, - HolderID: addr.Bytes(), - }) + currentTokenHolder, err := qtx.GetTokenHolder(ctx, queries.GetTokenHolderParams{ + TokenID: token.Address.Bytes(), + ChainID: token.ChainID, + ExternalID: token.ExternalID, + HolderID: addr.Bytes(), + }) if err != nil { if !errors.Is(sql.ErrNoRows, err) { return err From c38938a1656eef1f6ca8547414a42aa71dc045a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Fri, 26 Jan 2024 20:24:25 +0100 Subject: [PATCH 18/35] unused tables removed --- db/migrations/0003_census3.sql | 24 ++++++++++++++ db/queries/blocks.sql | 19 ----------- db/sqlc/blocks.sql.go | 60 ---------------------------------- 3 files changed, 24 insertions(+), 79 deletions(-) delete mode 100644 db/queries/blocks.sql delete mode 100644 db/sqlc/blocks.sql.go diff --git a/db/migrations/0003_census3.sql b/db/migrations/0003_census3.sql index 163d03d9..7c64de97 100644 --- a/db/migrations/0003_census3.sql +++ b/db/migrations/0003_census3.sql @@ -1,5 +1,29 @@ -- +goose Up + +-- prepare token_holders table to delete blocks, holders and census_blocks tables +CREATE TABLE token_holders_backup ( + token_id BLOB NOT NULL, + holder_id BLOB NOT NULL, + balance TEXT NOT NULL, + block_id INTEGER NOT NULL, + chain_id INTEGER NOT NULL, + external_id TEXT NULL DEFAULT '', + PRIMARY KEY (token_id, holder_id, block_id, chain_id, external_id), + FOREIGN KEY (token_id) REFERENCES tokens(id) ON DELETE CASCADE +); +CREATE INDEX idx_token_holders_token_id ON token_holders(token_id); +CREATE INDEX idx_token_holders_holder_id ON token_holders(holder_id); +CREATE INDEX idx_token_holders_block_id ON token_holders(block_id); + +INSERT INTO token_holders_backup SELECT * FROM token_holders; +DROP TABLE token_holders; +ALTER TABLE token_holders_backup RENAME TO token_holders; + +DELETE FROM blocks; +DELETE FROM holders; +DELETE FROM census_blocks; + DELETE FROM token_types; UPDATE sqlite_sequence SET seq = 0 WHERE name = 'token_types'; INSERT INTO token_types (id, type_name) VALUES (0, 'unknown'); diff --git a/db/queries/blocks.sql b/db/queries/blocks.sql deleted file mode 100644 index 4903cf3f..00000000 --- a/db/queries/blocks.sql +++ /dev/null @@ -1,19 +0,0 @@ --- name: BlockByID :one -SELECT * FROM blocks -WHERE id = ? -LIMIT 1; - --- name: CreateBlock :execresult -INSERT INTO blocks ( - id, - timestamp, - root_hash -) -VALUES ( - ?, ?, ? -); - --- name: LastBlock :one -SELECT id FROM blocks -ORDER BY id DESC -LIMIT 1; \ No newline at end of file diff --git a/db/sqlc/blocks.sql.go b/db/sqlc/blocks.sql.go deleted file mode 100644 index 2b39e6ed..00000000 --- a/db/sqlc/blocks.sql.go +++ /dev/null @@ -1,60 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.25.0 -// source: blocks.sql - -package queries - -import ( - "context" - "database/sql" - - "github.com/vocdoni/census3/db/annotations" -) - -const blockByID = `-- name: BlockByID :one -SELECT id, timestamp, root_hash FROM blocks -WHERE id = ? -LIMIT 1 -` - -func (q *Queries) BlockByID(ctx context.Context, id uint64) (Block, error) { - row := q.db.QueryRowContext(ctx, blockByID, id) - var i Block - err := row.Scan(&i.ID, &i.Timestamp, &i.RootHash) - return i, err -} - -const createBlock = `-- name: CreateBlock :execresult -INSERT INTO blocks ( - id, - timestamp, - root_hash -) -VALUES ( - ?, ?, ? -) -` - -type CreateBlockParams struct { - ID uint64 - Timestamp string - RootHash annotations.Hash -} - -func (q *Queries) CreateBlock(ctx context.Context, arg CreateBlockParams) (sql.Result, error) { - return q.db.ExecContext(ctx, createBlock, arg.ID, arg.Timestamp, arg.RootHash) -} - -const lastBlock = `-- name: LastBlock :one -SELECT id FROM blocks -ORDER BY id DESC -LIMIT 1 -` - -func (q *Queries) LastBlock(ctx context.Context) (uint64, error) { - row := q.db.QueryRowContext(ctx, lastBlock) - var id uint64 - err := row.Scan(&id) - return id, err -} From ce0838b161345c74949cca4be214fb431e063ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Fri, 26 Jan 2024 21:36:00 +0100 Subject: [PATCH 19/35] unifiying multiple sources of token types --- api/tokens.go | 4 +- cmd/census3/main.go | 20 ++++++-- db/migrations/0003_census3.sql | 7 ++- db/queries/tokenTypes.sql | 21 +-------- db/sqlc/models.go | 15 ------ db/sqlc/tokenTypes.sql.go | 47 +++---------------- scanner/providers/gitcoin/gitcoin_provider.go | 5 ++ scanner/providers/holders_provider.go | 1 + scanner/providers/poap/poap_provider.go | 6 +++ scanner/providers/web3/erc20_provider.go | 4 ++ scanner/providers/web3/erc721_provider.go | 4 ++ scanner/providers/web3/erc777_provider.go | 4 ++ scanner/scanner.go | 21 ++++++++- 13 files changed, 75 insertions(+), 84 deletions(-) diff --git a/api/tokens.go b/api/tokens.go index ee0b8b2e..ccca292e 100644 --- a/api/tokens.go +++ b/api/tokens.go @@ -581,8 +581,8 @@ func (capi *census3API) isTokenHolder(msg *api.APIdata, ctx *httprouter.HTTPCont // supported types of token contracts. func (capi *census3API) getTokenTypes(msg *api.APIdata, ctx *httprouter.HTTPContext) error { supportedTypes := []string{} - for _, supportedType := range providers.TokenTypeStringMap { - supportedTypes = append(supportedTypes, supportedType) + for _, provider := range capi.holderProviders { + supportedTypes = append(supportedTypes, provider.TypeName()) } res, err := json.Marshal(TokenTypesResponse{supportedTypes}) if err != nil { diff --git a/cmd/census3/main.go b/cmd/census3/main.go index 6faab0c1..1c8e88bb 100644 --- a/cmd/census3/main.go +++ b/cmd/census3/main.go @@ -142,17 +142,23 @@ func main() { erc20Provider := new(web3.ERC20HolderProvider) if err := erc20Provider.Init(web3.Web3ProviderConfig{Endpoints: w3p}); err != nil { log.Fatal(err) + return } erc721Provider := new(web3.ERC721HolderProvider) if err := erc721Provider.Init(web3.Web3ProviderConfig{Endpoints: w3p}); err != nil { log.Fatal(err) + return } erc777Provider := new(web3.ERC777HolderProvider) if err := erc777Provider.Init(web3.Web3ProviderConfig{Endpoints: w3p}); err != nil { log.Fatal(err) + return } // set the providers in the scanner and the API - hc.SetProviders(erc20Provider, erc721Provider, erc777Provider) + if err := hc.SetProviders(erc20Provider, erc721Provider, erc777Provider); err != nil { + log.Fatal(err) + return + } apiProviders := map[uint64]providers.HolderProvider{ erc20Provider.Type(): erc20Provider, erc721Provider.Type(): erc721Provider, @@ -166,8 +172,12 @@ func main() { AccessToken: config.poapAuthToken, }); err != nil { log.Fatal(err) + return + } + if err := hc.SetProviders(poapProvider); err != nil { + log.Fatal(err) + return } - hc.SetProviders(poapProvider) apiProviders[poapProvider.Type()] = poapProvider } if config.gitcoinEndpoint != "" { @@ -178,8 +188,12 @@ func main() { Cooldown: config.gitcoinCooldown, }); err != nil { log.Fatal(err) + return + } + if err := hc.SetProviders(gitcoinProvider); err != nil { + log.Fatal(err) + return } - hc.SetProviders(gitcoinProvider) apiProviders[gitcoinProvider.Type()] = gitcoinProvider } diff --git a/db/migrations/0003_census3.sql b/db/migrations/0003_census3.sql index 7c64de97..a7e38479 100644 --- a/db/migrations/0003_census3.sql +++ b/db/migrations/0003_census3.sql @@ -19,10 +19,9 @@ CREATE INDEX idx_token_holders_block_id ON token_holders(block_id); INSERT INTO token_holders_backup SELECT * FROM token_holders; DROP TABLE token_holders; ALTER TABLE token_holders_backup RENAME TO token_holders; - -DELETE FROM blocks; -DELETE FROM holders; -DELETE FROM census_blocks; +DROP TABLE blocks; +DROP TABLE holders; +DROP TABLE census_blocks; DELETE FROM token_types; UPDATE sqlite_sequence SET seq = 0 WHERE name = 'token_types'; diff --git a/db/queries/tokenTypes.sql b/db/queries/tokenTypes.sql index ef65ec88..eb58c6b1 100644 --- a/db/queries/tokenTypes.sql +++ b/db/queries/tokenTypes.sql @@ -2,25 +2,8 @@ SELECT * FROM token_types ORDER BY id; --- name: TokenTypeByID :one -SELECT * FROM token_types -WHERE id = ? -LIMIT 1; - --- name: TokenTypeByName :one -SELECT * FROM token_types -WHERE type_name = ? -LIMIT 1; - -- name: CreateTokenType :execresult -INSERT INTO token_types (type_name) -VALUES (?); +INSERT INTO token_types (id, type_name) VALUES (?, ?); -- name: UpdateTokenType :execresult -UPDATE token_types -SET type_name = sqlc.arg(type_name) -WHERE id = sqlc.arg(id); - --- name: DeleteTokenType :execresult -DELETE FROM token_types -WHERE id = ?; \ No newline at end of file +UPDATE token_types SET type_name = ? WHERE id = ?; \ No newline at end of file diff --git a/db/sqlc/models.go b/db/sqlc/models.go index 4ddf36e0..e198d8dd 100644 --- a/db/sqlc/models.go +++ b/db/sqlc/models.go @@ -11,17 +11,6 @@ import ( "github.com/vocdoni/census3/db/annotations" ) -type Block struct { - ID uint64 - Timestamp string - RootHash annotations.Hash -} - -type CensusBlock struct { - CensusID uint64 - BlockID uint64 -} - type Censuse struct { ID uint64 StrategyID uint64 @@ -34,10 +23,6 @@ type Censuse struct { Accuracy float64 } -type Holder struct { - ID annotations.Address -} - type Strategy struct { ID uint64 Predicate string diff --git a/db/sqlc/tokenTypes.sql.go b/db/sqlc/tokenTypes.sql.go index 53f28194..ef3e1f9d 100644 --- a/db/sqlc/tokenTypes.sql.go +++ b/db/sqlc/tokenTypes.sql.go @@ -11,21 +11,16 @@ import ( ) const createTokenType = `-- name: CreateTokenType :execresult -INSERT INTO token_types (type_name) -VALUES (?) +INSERT INTO token_types (id, type_name) VALUES (?, ?) ` -func (q *Queries) CreateTokenType(ctx context.Context, typeName string) (sql.Result, error) { - return q.db.ExecContext(ctx, createTokenType, typeName) +type CreateTokenTypeParams struct { + ID uint64 + TypeName string } -const deleteTokenType = `-- name: DeleteTokenType :execresult -DELETE FROM token_types -WHERE id = ? -` - -func (q *Queries) DeleteTokenType(ctx context.Context, id uint64) (sql.Result, error) { - return q.db.ExecContext(ctx, deleteTokenType, id) +func (q *Queries) CreateTokenType(ctx context.Context, arg CreateTokenTypeParams) (sql.Result, error) { + return q.db.ExecContext(ctx, createTokenType, arg.ID, arg.TypeName) } const listTokenTypes = `-- name: ListTokenTypes :many @@ -56,36 +51,8 @@ func (q *Queries) ListTokenTypes(ctx context.Context) ([]TokenType, error) { return items, nil } -const tokenTypeByID = `-- name: TokenTypeByID :one -SELECT id, type_name FROM token_types -WHERE id = ? -LIMIT 1 -` - -func (q *Queries) TokenTypeByID(ctx context.Context, id uint64) (TokenType, error) { - row := q.db.QueryRowContext(ctx, tokenTypeByID, id) - var i TokenType - err := row.Scan(&i.ID, &i.TypeName) - return i, err -} - -const tokenTypeByName = `-- name: TokenTypeByName :one -SELECT id, type_name FROM token_types -WHERE type_name = ? -LIMIT 1 -` - -func (q *Queries) TokenTypeByName(ctx context.Context, typeName string) (TokenType, error) { - row := q.db.QueryRowContext(ctx, tokenTypeByName, typeName) - var i TokenType - err := row.Scan(&i.ID, &i.TypeName) - return i, err -} - const updateTokenType = `-- name: UpdateTokenType :execresult -UPDATE token_types -SET type_name = ? -WHERE id = ? +UPDATE token_types SET type_name = ? WHERE id = ? ` type UpdateTokenTypeParams struct { diff --git a/scanner/providers/gitcoin/gitcoin_provider.go b/scanner/providers/gitcoin/gitcoin_provider.go index eec1647d..738f2ec8 100644 --- a/scanner/providers/gitcoin/gitcoin_provider.go +++ b/scanner/providers/gitcoin/gitcoin_provider.go @@ -254,6 +254,11 @@ func (g *GitcoinPassport) Type() uint64 { return providers.CONTRACT_TYPE_GITCOIN } +// TypeName returns the type name of the Gitcoin Passport contract. +func (g *GitcoinPassport) TypeName() string { + return providers.TokenTypeStringMap[providers.CONTRACT_TYPE_GITCOIN] +} + // ChainID returns the chain ID of the Gitcoin Passport contract. func (g *GitcoinPassport) ChainID() uint64 { return 1 diff --git a/scanner/providers/holders_provider.go b/scanner/providers/holders_provider.go index bc1216dc..316c8b69 100644 --- a/scanner/providers/holders_provider.go +++ b/scanner/providers/holders_provider.go @@ -34,6 +34,7 @@ type HolderProvider interface { // Token realated methods Address() common.Address Type() uint64 + TypeName() string ChainID() uint64 Name(id []byte) (string, error) Symbol(id []byte) (string, error) diff --git a/scanner/providers/poap/poap_provider.go b/scanner/providers/poap/poap_provider.go index 36ce8694..a4fbc78b 100644 --- a/scanner/providers/poap/poap_provider.go +++ b/scanner/providers/poap/poap_provider.go @@ -180,6 +180,12 @@ func (p *POAPHolderProvider) Type() uint64 { return providers.CONTRACT_TYPE_POAP } +// TypeName returns the type name of the POAP token. By default it returns the +// string "POAP". +func (p *POAPHolderProvider) TypeName() string { + return providers.TokenTypeStringMap[providers.CONTRACT_TYPE_POAP] +} + // ChainID method is not implemented in the POAP external provider. By default 1. func (p *POAPHolderProvider) ChainID() uint64 { return 1 diff --git a/scanner/providers/web3/erc20_provider.go b/scanner/providers/web3/erc20_provider.go index c6a98e2a..8f859ef7 100644 --- a/scanner/providers/web3/erc20_provider.go +++ b/scanner/providers/web3/erc20_provider.go @@ -162,6 +162,10 @@ func (p *ERC20HolderProvider) Type() uint64 { return providers.CONTRACT_TYPE_ERC20 } +func (p *ERC20HolderProvider) TypeName() string { + return providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC20] +} + func (p *ERC20HolderProvider) ChainID() uint64 { return p.chainID } diff --git a/scanner/providers/web3/erc721_provider.go b/scanner/providers/web3/erc721_provider.go index 204fe313..9af4614a 100644 --- a/scanner/providers/web3/erc721_provider.go +++ b/scanner/providers/web3/erc721_provider.go @@ -162,6 +162,10 @@ func (p *ERC721HolderProvider) Type() uint64 { return providers.CONTRACT_TYPE_ERC721 } +func (p *ERC721HolderProvider) TypeName() string { + return providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC721] +} + func (p *ERC721HolderProvider) ChainID() uint64 { return p.chainID } diff --git a/scanner/providers/web3/erc777_provider.go b/scanner/providers/web3/erc777_provider.go index a066e1e1..83635ca6 100644 --- a/scanner/providers/web3/erc777_provider.go +++ b/scanner/providers/web3/erc777_provider.go @@ -161,6 +161,10 @@ func (p *ERC777HolderProvider) Type() uint64 { return providers.CONTRACT_TYPE_ERC777 } +func (p *ERC777HolderProvider) TypeName() string { + return providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC777] +} + func (p *ERC777HolderProvider) ChainID() uint64 { return p.chainID } diff --git a/scanner/scanner.go b/scanner/scanner.go index 7ffed7db..e7bcd12a 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -7,6 +7,7 @@ import ( "fmt" "math/big" "sort" + "strings" "sync" "time" @@ -64,10 +65,28 @@ func NewScanner(db *db.DB, networks web3.NetworkEndpoints, coolDown time.Duratio // SetProviders sets the providers that the scanner will use to get the holders // of the tokens. -func (s *Scanner) SetProviders(newProviders ...providers.HolderProvider) { +func (s *Scanner) SetProviders(newProviders ...providers.HolderProvider) error { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + // create a tx to use it in the following queries for _, provider := range newProviders { + if _, err := s.db.QueriesRW.CreateTokenType(ctx, queries.CreateTokenTypeParams{ + ID: provider.Type(), + TypeName: provider.TypeName(), + }); err != nil { + if !strings.Contains(err.Error(), "UNIQUE constraint failed") { + return err + } + if _, err := s.db.QueriesRW.UpdateTokenType(ctx, queries.UpdateTokenTypeParams{ + ID: provider.Type(), + TypeName: provider.TypeName(), + }); err != nil { + return err + } + } s.providers[provider.Type()] = provider } + return nil } // Start starts the scanner. It starts a loop that scans the tokens in the From 85f508e38f4818d3a8b59c247ee21c03d27d7b2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Fri, 26 Jan 2024 21:42:25 +0100 Subject: [PATCH 20/35] deleting unused db queries --- api/holders.go | 4 +- api/tokens.go | 4 +- db/migrations/0003_census3.sql | 3 - db/queries/tokens.sql | 12 +-- db/sqlc/tokens.sql.go | 141 +++++++++------------------------ scanner/scanner.go | 4 +- 6 files changed, 44 insertions(+), 124 deletions(-) diff --git a/api/holders.go b/api/holders.go index 3f943a96..a3a35c4d 100644 --- a/api/holders.go +++ b/api/holders.go @@ -83,8 +83,8 @@ func (capi *census3API) listHoldersAtLastBlock(address common.Address, // get token information from the database internalCtx, cancel := context.WithTimeout(context.Background(), time.Minute*10) defer cancel() - tokenData, err := capi.db.QueriesRO.TokenByIDAndChainIDAndExternalID(internalCtx, - queries.TokenByIDAndChainIDAndExternalIDParams{ + tokenData, err := capi.db.QueriesRO.GetToken(internalCtx, + queries.GetTokenParams{ ID: address.Bytes(), ChainID: chainID, ExternalID: externalID, diff --git a/api/tokens.go b/api/tokens.go index ccca292e..034438e4 100644 --- a/api/tokens.go +++ b/api/tokens.go @@ -455,8 +455,8 @@ func (capi *census3API) getToken(msg *api.APIdata, ctx *httprouter.HTTPContext) // get token information from the database internalCtx, cancel := context.WithTimeout(ctx.Request.Context(), getTokenTimeout) defer cancel() - tokenData, err := capi.db.QueriesRO.TokenByIDAndChainIDAndExternalID(internalCtx, - queries.TokenByIDAndChainIDAndExternalIDParams{ + tokenData, err := capi.db.QueriesRO.GetToken(internalCtx, + queries.GetTokenParams{ ID: address.Bytes(), ChainID: uint64(chainID), ExternalID: externalID, diff --git a/db/migrations/0003_census3.sql b/db/migrations/0003_census3.sql index a7e38479..19b0ddf0 100644 --- a/db/migrations/0003_census3.sql +++ b/db/migrations/0003_census3.sql @@ -12,9 +12,6 @@ CREATE TABLE token_holders_backup ( PRIMARY KEY (token_id, holder_id, block_id, chain_id, external_id), FOREIGN KEY (token_id) REFERENCES tokens(id) ON DELETE CASCADE ); -CREATE INDEX idx_token_holders_token_id ON token_holders(token_id); -CREATE INDEX idx_token_holders_holder_id ON token_holders(holder_id); -CREATE INDEX idx_token_holders_block_id ON token_holders(block_id); INSERT INTO token_holders_backup SELECT * FROM token_holders; DROP TABLE token_holders; diff --git a/db/queries/tokens.sql b/db/queries/tokens.sql index 31382464..92f84675 100644 --- a/db/queries/tokens.sql +++ b/db/queries/tokens.sql @@ -26,17 +26,7 @@ SELECT * FROM ( LIMIT ? ) as token ORDER BY token.id ASC; --- name: TokenByID :one -SELECT * FROM tokens -WHERE id = ? -LIMIT 1; - --- name: TokenByIDAndChainID :one -SELECT * FROM tokens -WHERE id = ? AND chain_id = ? -LIMIT 1; - --- name: TokenByIDAndChainIDAndExternalID :one +-- name: GetToken :one SELECT * FROM tokens WHERE id = ? AND chain_id = ? AND external_id = ? LIMIT 1; diff --git a/db/sqlc/tokens.sql.go b/db/sqlc/tokens.sql.go index b8eac82d..c9e212ef 100644 --- a/db/sqlc/tokens.sql.go +++ b/db/sqlc/tokens.sql.go @@ -155,6 +155,43 @@ func (q *Queries) ExistsTokenByChainIDAndExternalID(ctx context.Context, arg Exi return exists, err } +const getToken = `-- name: GetToken :one +SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM tokens +WHERE id = ? AND chain_id = ? AND external_id = ? +LIMIT 1 +` + +type GetTokenParams struct { + ID annotations.Address + ChainID uint64 + ExternalID string +} + +func (q *Queries) GetToken(ctx context.Context, arg GetTokenParams) (Token, error) { + row := q.db.QueryRowContext(ctx, getToken, arg.ID, arg.ChainID, arg.ExternalID) + var i Token + err := row.Scan( + &i.ID, + &i.Name, + &i.Symbol, + &i.Decimals, + &i.TotalSupply, + &i.CreationBlock, + &i.TypeID, + &i.Synced, + &i.Tags, + &i.ChainID, + &i.ChainAddress, + &i.ExternalID, + &i.DefaultStrategy, + &i.IconUri, + &i.CreatedAt, + &i.LastBlock, + &i.AnalysedTransfers, + ) + return i, err +} + const listLastNoSyncedTokens = `-- name: ListLastNoSyncedTokens :many SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM tokens WHERE strftime('%s', 'now') - strftime('%s', created_at) <= 600 @@ -403,110 +440,6 @@ func (q *Queries) PrevTokensPage(ctx context.Context, arg PrevTokensPageParams) return items, nil } -const tokenByID = `-- name: TokenByID :one -SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM tokens -WHERE id = ? -LIMIT 1 -` - -func (q *Queries) TokenByID(ctx context.Context, id annotations.Address) (Token, error) { - row := q.db.QueryRowContext(ctx, tokenByID, id) - var i Token - err := row.Scan( - &i.ID, - &i.Name, - &i.Symbol, - &i.Decimals, - &i.TotalSupply, - &i.CreationBlock, - &i.TypeID, - &i.Synced, - &i.Tags, - &i.ChainID, - &i.ChainAddress, - &i.ExternalID, - &i.DefaultStrategy, - &i.IconUri, - &i.CreatedAt, - &i.LastBlock, - &i.AnalysedTransfers, - ) - return i, err -} - -const tokenByIDAndChainID = `-- name: TokenByIDAndChainID :one -SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM tokens -WHERE id = ? AND chain_id = ? -LIMIT 1 -` - -type TokenByIDAndChainIDParams struct { - ID annotations.Address - ChainID uint64 -} - -func (q *Queries) TokenByIDAndChainID(ctx context.Context, arg TokenByIDAndChainIDParams) (Token, error) { - row := q.db.QueryRowContext(ctx, tokenByIDAndChainID, arg.ID, arg.ChainID) - var i Token - err := row.Scan( - &i.ID, - &i.Name, - &i.Symbol, - &i.Decimals, - &i.TotalSupply, - &i.CreationBlock, - &i.TypeID, - &i.Synced, - &i.Tags, - &i.ChainID, - &i.ChainAddress, - &i.ExternalID, - &i.DefaultStrategy, - &i.IconUri, - &i.CreatedAt, - &i.LastBlock, - &i.AnalysedTransfers, - ) - return i, err -} - -const tokenByIDAndChainIDAndExternalID = `-- name: TokenByIDAndChainIDAndExternalID :one -SELECT id, name, symbol, decimals, total_supply, creation_block, type_id, synced, tags, chain_id, chain_address, external_id, default_strategy, icon_uri, created_at, last_block, analysed_transfers FROM tokens -WHERE id = ? AND chain_id = ? AND external_id = ? -LIMIT 1 -` - -type TokenByIDAndChainIDAndExternalIDParams struct { - ID annotations.Address - ChainID uint64 - ExternalID string -} - -func (q *Queries) TokenByIDAndChainIDAndExternalID(ctx context.Context, arg TokenByIDAndChainIDAndExternalIDParams) (Token, error) { - row := q.db.QueryRowContext(ctx, tokenByIDAndChainIDAndExternalID, arg.ID, arg.ChainID, arg.ExternalID) - var i Token - err := row.Scan( - &i.ID, - &i.Name, - &i.Symbol, - &i.Decimals, - &i.TotalSupply, - &i.CreationBlock, - &i.TypeID, - &i.Synced, - &i.Tags, - &i.ChainID, - &i.ChainAddress, - &i.ExternalID, - &i.DefaultStrategy, - &i.IconUri, - &i.CreatedAt, - &i.LastBlock, - &i.AnalysedTransfers, - ) - return i, err -} - const tokensByStrategyID = `-- name: TokensByStrategyID :many SELECT t.id, t.name, t.symbol, t.decimals, t.total_supply, t.creation_block, t.type_id, t.synced, t.tags, t.chain_id, t.chain_address, t.external_id, t.default_strategy, t.icon_uri, t.created_at, t.last_block, t.analysed_transfers, st.strategy_id, st.token_id, st.min_balance, st.chain_id, st.external_id FROM tokens t JOIN strategy_tokens st ON st.token_id = t.id diff --git a/scanner/scanner.go b/scanner/scanner.go index e7bcd12a..b44d6afe 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -385,8 +385,8 @@ func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, } }() qtx := s.db.QueriesRW.WithTx(tx) - tokenInfo, err := qtx.TokenByIDAndChainIDAndExternalID(internalCtx, - queries.TokenByIDAndChainIDAndExternalIDParams{ + tokenInfo, err := qtx.GetToken(internalCtx, + queries.GetTokenParams{ ID: token.Address.Bytes(), ChainID: token.ChainID, ExternalID: token.ExternalID, From dffef2b2b5a1448a18247ca1433b7df4c1c545f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Fri, 26 Jan 2024 22:03:04 +0100 Subject: [PATCH 21/35] remove erc1155 contract --- contracts/erc/erc1155/ERC1155.abi | 1 - contracts/erc/erc1155/erc1155.go | 1026 ----------------------------- 2 files changed, 1027 deletions(-) delete mode 100644 contracts/erc/erc1155/ERC1155.abi delete mode 100644 contracts/erc/erc1155/erc1155.go diff --git a/contracts/erc/erc1155/ERC1155.abi b/contracts/erc/erc1155/ERC1155.abi deleted file mode 100644 index e91c0a4c..00000000 --- a/contracts/erc/erc1155/ERC1155.abi +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"string","name":"uri_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/contracts/erc/erc1155/erc1155.go b/contracts/erc/erc1155/erc1155.go deleted file mode 100644 index 7a28f8e6..00000000 --- a/contracts/erc/erc1155/erc1155.go +++ /dev/null @@ -1,1026 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package ERC1155Contract - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// ERC1155ContractMetaData contains all meta data concerning the ERC1155Contract contract. -var ERC1155ContractMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"uri_\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", -} - -// ERC1155ContractABI is the input ABI used to generate the binding from. -// Deprecated: Use ERC1155ContractMetaData.ABI instead. -var ERC1155ContractABI = ERC1155ContractMetaData.ABI - -// ERC1155Contract is an auto generated Go binding around an Ethereum contract. -type ERC1155Contract struct { - ERC1155ContractCaller // Read-only binding to the contract - ERC1155ContractTransactor // Write-only binding to the contract - ERC1155ContractFilterer // Log filterer for contract events -} - -// ERC1155ContractCaller is an auto generated read-only Go binding around an Ethereum contract. -type ERC1155ContractCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ERC1155ContractTransactor is an auto generated write-only Go binding around an Ethereum contract. -type ERC1155ContractTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ERC1155ContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type ERC1155ContractFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ERC1155ContractSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type ERC1155ContractSession struct { - Contract *ERC1155Contract // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ERC1155ContractCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type ERC1155ContractCallerSession struct { - Contract *ERC1155ContractCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// ERC1155ContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type ERC1155ContractTransactorSession struct { - Contract *ERC1155ContractTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ERC1155ContractRaw is an auto generated low-level Go binding around an Ethereum contract. -type ERC1155ContractRaw struct { - Contract *ERC1155Contract // Generic contract binding to access the raw methods on -} - -// ERC1155ContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type ERC1155ContractCallerRaw struct { - Contract *ERC1155ContractCaller // Generic read-only contract binding to access the raw methods on -} - -// ERC1155ContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type ERC1155ContractTransactorRaw struct { - Contract *ERC1155ContractTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewERC1155Contract creates a new instance of ERC1155Contract, bound to a specific deployed contract. -func NewERC1155Contract(address common.Address, backend bind.ContractBackend) (*ERC1155Contract, error) { - contract, err := bindERC1155Contract(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &ERC1155Contract{ERC1155ContractCaller: ERC1155ContractCaller{contract: contract}, ERC1155ContractTransactor: ERC1155ContractTransactor{contract: contract}, ERC1155ContractFilterer: ERC1155ContractFilterer{contract: contract}}, nil -} - -// NewERC1155ContractCaller creates a new read-only instance of ERC1155Contract, bound to a specific deployed contract. -func NewERC1155ContractCaller(address common.Address, caller bind.ContractCaller) (*ERC1155ContractCaller, error) { - contract, err := bindERC1155Contract(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &ERC1155ContractCaller{contract: contract}, nil -} - -// NewERC1155ContractTransactor creates a new write-only instance of ERC1155Contract, bound to a specific deployed contract. -func NewERC1155ContractTransactor(address common.Address, transactor bind.ContractTransactor) (*ERC1155ContractTransactor, error) { - contract, err := bindERC1155Contract(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &ERC1155ContractTransactor{contract: contract}, nil -} - -// NewERC1155ContractFilterer creates a new log filterer instance of ERC1155Contract, bound to a specific deployed contract. -func NewERC1155ContractFilterer(address common.Address, filterer bind.ContractFilterer) (*ERC1155ContractFilterer, error) { - contract, err := bindERC1155Contract(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &ERC1155ContractFilterer{contract: contract}, nil -} - -// bindERC1155Contract binds a generic wrapper to an already deployed contract. -func bindERC1155Contract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := ERC1155ContractMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_ERC1155Contract *ERC1155ContractRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _ERC1155Contract.Contract.ERC1155ContractCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_ERC1155Contract *ERC1155ContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _ERC1155Contract.Contract.ERC1155ContractTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_ERC1155Contract *ERC1155ContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _ERC1155Contract.Contract.ERC1155ContractTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_ERC1155Contract *ERC1155ContractCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _ERC1155Contract.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_ERC1155Contract *ERC1155ContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _ERC1155Contract.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_ERC1155Contract *ERC1155ContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _ERC1155Contract.Contract.contract.Transact(opts, method, params...) -} - -// BalanceOf is a free data retrieval call binding the contract method 0x00fdd58e. -// -// Solidity: function balanceOf(address account, uint256 id) view returns(uint256) -func (_ERC1155Contract *ERC1155ContractCaller) BalanceOf(opts *bind.CallOpts, account common.Address, id *big.Int) (*big.Int, error) { - var out []interface{} - err := _ERC1155Contract.contract.Call(opts, &out, "balanceOf", account, id) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// BalanceOf is a free data retrieval call binding the contract method 0x00fdd58e. -// -// Solidity: function balanceOf(address account, uint256 id) view returns(uint256) -func (_ERC1155Contract *ERC1155ContractSession) BalanceOf(account common.Address, id *big.Int) (*big.Int, error) { - return _ERC1155Contract.Contract.BalanceOf(&_ERC1155Contract.CallOpts, account, id) -} - -// BalanceOf is a free data retrieval call binding the contract method 0x00fdd58e. -// -// Solidity: function balanceOf(address account, uint256 id) view returns(uint256) -func (_ERC1155Contract *ERC1155ContractCallerSession) BalanceOf(account common.Address, id *big.Int) (*big.Int, error) { - return _ERC1155Contract.Contract.BalanceOf(&_ERC1155Contract.CallOpts, account, id) -} - -// BalanceOfBatch is a free data retrieval call binding the contract method 0x4e1273f4. -// -// Solidity: function balanceOfBatch(address[] accounts, uint256[] ids) view returns(uint256[]) -func (_ERC1155Contract *ERC1155ContractCaller) BalanceOfBatch(opts *bind.CallOpts, accounts []common.Address, ids []*big.Int) ([]*big.Int, error) { - var out []interface{} - err := _ERC1155Contract.contract.Call(opts, &out, "balanceOfBatch", accounts, ids) - - if err != nil { - return *new([]*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int) - - return out0, err - -} - -// BalanceOfBatch is a free data retrieval call binding the contract method 0x4e1273f4. -// -// Solidity: function balanceOfBatch(address[] accounts, uint256[] ids) view returns(uint256[]) -func (_ERC1155Contract *ERC1155ContractSession) BalanceOfBatch(accounts []common.Address, ids []*big.Int) ([]*big.Int, error) { - return _ERC1155Contract.Contract.BalanceOfBatch(&_ERC1155Contract.CallOpts, accounts, ids) -} - -// BalanceOfBatch is a free data retrieval call binding the contract method 0x4e1273f4. -// -// Solidity: function balanceOfBatch(address[] accounts, uint256[] ids) view returns(uint256[]) -func (_ERC1155Contract *ERC1155ContractCallerSession) BalanceOfBatch(accounts []common.Address, ids []*big.Int) ([]*big.Int, error) { - return _ERC1155Contract.Contract.BalanceOfBatch(&_ERC1155Contract.CallOpts, accounts, ids) -} - -// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. -// -// Solidity: function isApprovedForAll(address account, address operator) view returns(bool) -func (_ERC1155Contract *ERC1155ContractCaller) IsApprovedForAll(opts *bind.CallOpts, account common.Address, operator common.Address) (bool, error) { - var out []interface{} - err := _ERC1155Contract.contract.Call(opts, &out, "isApprovedForAll", account, operator) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. -// -// Solidity: function isApprovedForAll(address account, address operator) view returns(bool) -func (_ERC1155Contract *ERC1155ContractSession) IsApprovedForAll(account common.Address, operator common.Address) (bool, error) { - return _ERC1155Contract.Contract.IsApprovedForAll(&_ERC1155Contract.CallOpts, account, operator) -} - -// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. -// -// Solidity: function isApprovedForAll(address account, address operator) view returns(bool) -func (_ERC1155Contract *ERC1155ContractCallerSession) IsApprovedForAll(account common.Address, operator common.Address) (bool, error) { - return _ERC1155Contract.Contract.IsApprovedForAll(&_ERC1155Contract.CallOpts, account, operator) -} - -// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. -// -// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) -func (_ERC1155Contract *ERC1155ContractCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { - var out []interface{} - err := _ERC1155Contract.contract.Call(opts, &out, "supportsInterface", interfaceId) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. -// -// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) -func (_ERC1155Contract *ERC1155ContractSession) SupportsInterface(interfaceId [4]byte) (bool, error) { - return _ERC1155Contract.Contract.SupportsInterface(&_ERC1155Contract.CallOpts, interfaceId) -} - -// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. -// -// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) -func (_ERC1155Contract *ERC1155ContractCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { - return _ERC1155Contract.Contract.SupportsInterface(&_ERC1155Contract.CallOpts, interfaceId) -} - -// Uri is a free data retrieval call binding the contract method 0x0e89341c. -// -// Solidity: function uri(uint256 ) view returns(string) -func (_ERC1155Contract *ERC1155ContractCaller) Uri(opts *bind.CallOpts, arg0 *big.Int) (string, error) { - var out []interface{} - err := _ERC1155Contract.contract.Call(opts, &out, "uri", arg0) - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// Uri is a free data retrieval call binding the contract method 0x0e89341c. -// -// Solidity: function uri(uint256 ) view returns(string) -func (_ERC1155Contract *ERC1155ContractSession) Uri(arg0 *big.Int) (string, error) { - return _ERC1155Contract.Contract.Uri(&_ERC1155Contract.CallOpts, arg0) -} - -// Uri is a free data retrieval call binding the contract method 0x0e89341c. -// -// Solidity: function uri(uint256 ) view returns(string) -func (_ERC1155Contract *ERC1155ContractCallerSession) Uri(arg0 *big.Int) (string, error) { - return _ERC1155Contract.Contract.Uri(&_ERC1155Contract.CallOpts, arg0) -} - -// SafeBatchTransferFrom is a paid mutator transaction binding the contract method 0x2eb2c2d6. -// -// Solidity: function safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes data) returns() -func (_ERC1155Contract *ERC1155ContractTransactor) SafeBatchTransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, ids []*big.Int, amounts []*big.Int, data []byte) (*types.Transaction, error) { - return _ERC1155Contract.contract.Transact(opts, "safeBatchTransferFrom", from, to, ids, amounts, data) -} - -// SafeBatchTransferFrom is a paid mutator transaction binding the contract method 0x2eb2c2d6. -// -// Solidity: function safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes data) returns() -func (_ERC1155Contract *ERC1155ContractSession) SafeBatchTransferFrom(from common.Address, to common.Address, ids []*big.Int, amounts []*big.Int, data []byte) (*types.Transaction, error) { - return _ERC1155Contract.Contract.SafeBatchTransferFrom(&_ERC1155Contract.TransactOpts, from, to, ids, amounts, data) -} - -// SafeBatchTransferFrom is a paid mutator transaction binding the contract method 0x2eb2c2d6. -// -// Solidity: function safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes data) returns() -func (_ERC1155Contract *ERC1155ContractTransactorSession) SafeBatchTransferFrom(from common.Address, to common.Address, ids []*big.Int, amounts []*big.Int, data []byte) (*types.Transaction, error) { - return _ERC1155Contract.Contract.SafeBatchTransferFrom(&_ERC1155Contract.TransactOpts, from, to, ids, amounts, data) -} - -// SafeTransferFrom is a paid mutator transaction binding the contract method 0xf242432a. -// -// Solidity: function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data) returns() -func (_ERC1155Contract *ERC1155ContractTransactor) SafeTransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, id *big.Int, amount *big.Int, data []byte) (*types.Transaction, error) { - return _ERC1155Contract.contract.Transact(opts, "safeTransferFrom", from, to, id, amount, data) -} - -// SafeTransferFrom is a paid mutator transaction binding the contract method 0xf242432a. -// -// Solidity: function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data) returns() -func (_ERC1155Contract *ERC1155ContractSession) SafeTransferFrom(from common.Address, to common.Address, id *big.Int, amount *big.Int, data []byte) (*types.Transaction, error) { - return _ERC1155Contract.Contract.SafeTransferFrom(&_ERC1155Contract.TransactOpts, from, to, id, amount, data) -} - -// SafeTransferFrom is a paid mutator transaction binding the contract method 0xf242432a. -// -// Solidity: function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data) returns() -func (_ERC1155Contract *ERC1155ContractTransactorSession) SafeTransferFrom(from common.Address, to common.Address, id *big.Int, amount *big.Int, data []byte) (*types.Transaction, error) { - return _ERC1155Contract.Contract.SafeTransferFrom(&_ERC1155Contract.TransactOpts, from, to, id, amount, data) -} - -// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. -// -// Solidity: function setApprovalForAll(address operator, bool approved) returns() -func (_ERC1155Contract *ERC1155ContractTransactor) SetApprovalForAll(opts *bind.TransactOpts, operator common.Address, approved bool) (*types.Transaction, error) { - return _ERC1155Contract.contract.Transact(opts, "setApprovalForAll", operator, approved) -} - -// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. -// -// Solidity: function setApprovalForAll(address operator, bool approved) returns() -func (_ERC1155Contract *ERC1155ContractSession) SetApprovalForAll(operator common.Address, approved bool) (*types.Transaction, error) { - return _ERC1155Contract.Contract.SetApprovalForAll(&_ERC1155Contract.TransactOpts, operator, approved) -} - -// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. -// -// Solidity: function setApprovalForAll(address operator, bool approved) returns() -func (_ERC1155Contract *ERC1155ContractTransactorSession) SetApprovalForAll(operator common.Address, approved bool) (*types.Transaction, error) { - return _ERC1155Contract.Contract.SetApprovalForAll(&_ERC1155Contract.TransactOpts, operator, approved) -} - -// ERC1155ContractApprovalForAllIterator is returned from FilterApprovalForAll and is used to iterate over the raw logs and unpacked data for ApprovalForAll events raised by the ERC1155Contract contract. -type ERC1155ContractApprovalForAllIterator struct { - Event *ERC1155ContractApprovalForAll // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ERC1155ContractApprovalForAllIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ERC1155ContractApprovalForAll) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ERC1155ContractApprovalForAll) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ERC1155ContractApprovalForAllIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ERC1155ContractApprovalForAllIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ERC1155ContractApprovalForAll represents a ApprovalForAll event raised by the ERC1155Contract contract. -type ERC1155ContractApprovalForAll struct { - Account common.Address - Operator common.Address - Approved bool - Raw types.Log // Blockchain specific contextual infos -} - -// FilterApprovalForAll is a free log retrieval operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. -// -// Solidity: event ApprovalForAll(address indexed account, address indexed operator, bool approved) -func (_ERC1155Contract *ERC1155ContractFilterer) FilterApprovalForAll(opts *bind.FilterOpts, account []common.Address, operator []common.Address) (*ERC1155ContractApprovalForAllIterator, error) { - - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - var operatorRule []interface{} - for _, operatorItem := range operator { - operatorRule = append(operatorRule, operatorItem) - } - - logs, sub, err := _ERC1155Contract.contract.FilterLogs(opts, "ApprovalForAll", accountRule, operatorRule) - if err != nil { - return nil, err - } - return &ERC1155ContractApprovalForAllIterator{contract: _ERC1155Contract.contract, event: "ApprovalForAll", logs: logs, sub: sub}, nil -} - -// WatchApprovalForAll is a free log subscription operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. -// -// Solidity: event ApprovalForAll(address indexed account, address indexed operator, bool approved) -func (_ERC1155Contract *ERC1155ContractFilterer) WatchApprovalForAll(opts *bind.WatchOpts, sink chan<- *ERC1155ContractApprovalForAll, account []common.Address, operator []common.Address) (event.Subscription, error) { - - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - var operatorRule []interface{} - for _, operatorItem := range operator { - operatorRule = append(operatorRule, operatorItem) - } - - logs, sub, err := _ERC1155Contract.contract.WatchLogs(opts, "ApprovalForAll", accountRule, operatorRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ERC1155ContractApprovalForAll) - if err := _ERC1155Contract.contract.UnpackLog(event, "ApprovalForAll", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseApprovalForAll is a log parse operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. -// -// Solidity: event ApprovalForAll(address indexed account, address indexed operator, bool approved) -func (_ERC1155Contract *ERC1155ContractFilterer) ParseApprovalForAll(log types.Log) (*ERC1155ContractApprovalForAll, error) { - event := new(ERC1155ContractApprovalForAll) - if err := _ERC1155Contract.contract.UnpackLog(event, "ApprovalForAll", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// ERC1155ContractTransferBatchIterator is returned from FilterTransferBatch and is used to iterate over the raw logs and unpacked data for TransferBatch events raised by the ERC1155Contract contract. -type ERC1155ContractTransferBatchIterator struct { - Event *ERC1155ContractTransferBatch // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ERC1155ContractTransferBatchIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ERC1155ContractTransferBatch) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ERC1155ContractTransferBatch) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ERC1155ContractTransferBatchIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ERC1155ContractTransferBatchIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ERC1155ContractTransferBatch represents a TransferBatch event raised by the ERC1155Contract contract. -type ERC1155ContractTransferBatch struct { - Operator common.Address - From common.Address - To common.Address - Ids []*big.Int - Values []*big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterTransferBatch is a free log retrieval operation binding the contract event 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb. -// -// Solidity: event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values) -func (_ERC1155Contract *ERC1155ContractFilterer) FilterTransferBatch(opts *bind.FilterOpts, operator []common.Address, from []common.Address, to []common.Address) (*ERC1155ContractTransferBatchIterator, error) { - - var operatorRule []interface{} - for _, operatorItem := range operator { - operatorRule = append(operatorRule, operatorItem) - } - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _ERC1155Contract.contract.FilterLogs(opts, "TransferBatch", operatorRule, fromRule, toRule) - if err != nil { - return nil, err - } - return &ERC1155ContractTransferBatchIterator{contract: _ERC1155Contract.contract, event: "TransferBatch", logs: logs, sub: sub}, nil -} - -// WatchTransferBatch is a free log subscription operation binding the contract event 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb. -// -// Solidity: event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values) -func (_ERC1155Contract *ERC1155ContractFilterer) WatchTransferBatch(opts *bind.WatchOpts, sink chan<- *ERC1155ContractTransferBatch, operator []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { - - var operatorRule []interface{} - for _, operatorItem := range operator { - operatorRule = append(operatorRule, operatorItem) - } - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _ERC1155Contract.contract.WatchLogs(opts, "TransferBatch", operatorRule, fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ERC1155ContractTransferBatch) - if err := _ERC1155Contract.contract.UnpackLog(event, "TransferBatch", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseTransferBatch is a log parse operation binding the contract event 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb. -// -// Solidity: event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values) -func (_ERC1155Contract *ERC1155ContractFilterer) ParseTransferBatch(log types.Log) (*ERC1155ContractTransferBatch, error) { - event := new(ERC1155ContractTransferBatch) - if err := _ERC1155Contract.contract.UnpackLog(event, "TransferBatch", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// ERC1155ContractTransferSingleIterator is returned from FilterTransferSingle and is used to iterate over the raw logs and unpacked data for TransferSingle events raised by the ERC1155Contract contract. -type ERC1155ContractTransferSingleIterator struct { - Event *ERC1155ContractTransferSingle // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ERC1155ContractTransferSingleIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ERC1155ContractTransferSingle) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ERC1155ContractTransferSingle) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ERC1155ContractTransferSingleIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ERC1155ContractTransferSingleIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ERC1155ContractTransferSingle represents a TransferSingle event raised by the ERC1155Contract contract. -type ERC1155ContractTransferSingle struct { - Operator common.Address - From common.Address - To common.Address - Id *big.Int - Value *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterTransferSingle is a free log retrieval operation binding the contract event 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62. -// -// Solidity: event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value) -func (_ERC1155Contract *ERC1155ContractFilterer) FilterTransferSingle(opts *bind.FilterOpts, operator []common.Address, from []common.Address, to []common.Address) (*ERC1155ContractTransferSingleIterator, error) { - - var operatorRule []interface{} - for _, operatorItem := range operator { - operatorRule = append(operatorRule, operatorItem) - } - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _ERC1155Contract.contract.FilterLogs(opts, "TransferSingle", operatorRule, fromRule, toRule) - if err != nil { - return nil, err - } - return &ERC1155ContractTransferSingleIterator{contract: _ERC1155Contract.contract, event: "TransferSingle", logs: logs, sub: sub}, nil -} - -// WatchTransferSingle is a free log subscription operation binding the contract event 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62. -// -// Solidity: event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value) -func (_ERC1155Contract *ERC1155ContractFilterer) WatchTransferSingle(opts *bind.WatchOpts, sink chan<- *ERC1155ContractTransferSingle, operator []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { - - var operatorRule []interface{} - for _, operatorItem := range operator { - operatorRule = append(operatorRule, operatorItem) - } - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _ERC1155Contract.contract.WatchLogs(opts, "TransferSingle", operatorRule, fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ERC1155ContractTransferSingle) - if err := _ERC1155Contract.contract.UnpackLog(event, "TransferSingle", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseTransferSingle is a log parse operation binding the contract event 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62. -// -// Solidity: event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value) -func (_ERC1155Contract *ERC1155ContractFilterer) ParseTransferSingle(log types.Log) (*ERC1155ContractTransferSingle, error) { - event := new(ERC1155ContractTransferSingle) - if err := _ERC1155Contract.contract.UnpackLog(event, "TransferSingle", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// ERC1155ContractURIIterator is returned from FilterURI and is used to iterate over the raw logs and unpacked data for URI events raised by the ERC1155Contract contract. -type ERC1155ContractURIIterator struct { - Event *ERC1155ContractURI // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ERC1155ContractURIIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ERC1155ContractURI) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ERC1155ContractURI) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ERC1155ContractURIIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ERC1155ContractURIIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ERC1155ContractURI represents a URI event raised by the ERC1155Contract contract. -type ERC1155ContractURI struct { - Value string - Id *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterURI is a free log retrieval operation binding the contract event 0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b. -// -// Solidity: event URI(string value, uint256 indexed id) -func (_ERC1155Contract *ERC1155ContractFilterer) FilterURI(opts *bind.FilterOpts, id []*big.Int) (*ERC1155ContractURIIterator, error) { - - var idRule []interface{} - for _, idItem := range id { - idRule = append(idRule, idItem) - } - - logs, sub, err := _ERC1155Contract.contract.FilterLogs(opts, "URI", idRule) - if err != nil { - return nil, err - } - return &ERC1155ContractURIIterator{contract: _ERC1155Contract.contract, event: "URI", logs: logs, sub: sub}, nil -} - -// WatchURI is a free log subscription operation binding the contract event 0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b. -// -// Solidity: event URI(string value, uint256 indexed id) -func (_ERC1155Contract *ERC1155ContractFilterer) WatchURI(opts *bind.WatchOpts, sink chan<- *ERC1155ContractURI, id []*big.Int) (event.Subscription, error) { - - var idRule []interface{} - for _, idItem := range id { - idRule = append(idRule, idItem) - } - - logs, sub, err := _ERC1155Contract.contract.WatchLogs(opts, "URI", idRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ERC1155ContractURI) - if err := _ERC1155Contract.contract.UnpackLog(event, "URI", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseURI is a log parse operation binding the contract event 0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b. -// -// Solidity: event URI(string value, uint256 indexed id) -func (_ERC1155Contract *ERC1155ContractFilterer) ParseURI(log types.Log) (*ERC1155ContractURI, error) { - event := new(ERC1155ContractURI) - if err := _ERC1155Contract.contract.UnpackLog(event, "URI", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} From cb1e88695570f47f9f28c6a3ee5e5525f61fa5a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Mon, 29 Jan 2024 11:34:27 +0100 Subject: [PATCH 22/35] including warning into scanner/providers/types.go --- scanner/providers/types.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scanner/providers/types.go b/scanner/providers/types.go index 2d16689d..c70f283b 100644 --- a/scanner/providers/types.go +++ b/scanner/providers/types.go @@ -1,5 +1,14 @@ package providers +// This file contains the data types that can be implemented in the provider +// package. These types identify the type of contract being scanned and the type +// of token being scanned. However, not all contract types may be available. +// The available contract types depend on the providers that the scanner has +// configured. If a new token type is added, it must be added to this file, +// trying to maintain consistency with the existing token types, and avoiding +// using IDs that have already been used. If the IDs change, the database must +// be updated, correcting the IDs of the existing tokens. + const ( // CONTRACT TYPES CONTRACT_TYPE_UNKNOWN uint64 = iota From c4e8fbab2b49dd756c3420f799274a46f953bbc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Mon, 29 Jan 2024 11:41:33 +0100 Subject: [PATCH 23/35] readme updated --- README.md | 55 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index e369b629..4d57c7e4 100644 --- a/README.md +++ b/README.md @@ -27,17 +27,17 @@ Then, it allows creating a merkle tree census (compatible with [Vocdoni](https:/ The service suports the following token types: * ERC20 * ERC721 -* ERC1155 (*coming soon*) * ERC777 -* Nation3 (veNation) -* wANT * POAP +* Gitcoin Passport Score +* Gitcoin Passport Shields (*coming soon*) +* ERC1155 (*coming soon*) #### About censuses * The censuses are published on [IPFS](https://ipfs.tech/) after their creation. * Census3 uses [go.vocdoni.io/dvote/tree/arbo](go.vocdoni.io/dvote/tree/arbo) to build the census merkle trees. - * The censuses can be created with the holders of just one token or a combination of tokens, using **complex strategies** (*coming soon*). + * The censuses can be created with the holders of just one token or a combination of tokens, using **complex strategies**. * The censuses are *zk-friendly* and can also be used for anonymous voting. #### About complex strategies @@ -71,11 +71,18 @@ go build -o census3 ./cmd/census3 ```sh ./census3 --help Usage of ./census3: - --connectKey string connect group key for IPFS connect - --dataDir string data directory for persistent storage (default "<$HOME>/.census3") - --logLevel string log level (debug, info, warn, error) (default "info") - --port int HTTP port for the API (default 7788) - --web3Providers string the list of URL's of available web3 providers (separated with commas) + --adminToken string the admin UUID token for the API + --connectKey string connect group key for IPFS connect + --dataDir string data directory for persistent storage (default "~/.census3") + --logLevel string log level (debug, info, warn, error) (default "info") + --port int HTTP port for the API (default 7788) + --scannerCoolDown duration the time to wait before next scanner iteration (default 2m0s) + --initialTokens string path of the initial tokens json file + --web3Providers string the list of URLs of available web3 providers + --gitcoinEndpoint string Gitcoin Passport API access token + --gitcoinCooldown duration Gitcoin Passport API cooldown (default 6h0m0s) + --poapAPIEndpoint string POAP API endpoint + --poapAuthToken string POAP API access token ``` Example: @@ -91,21 +98,29 @@ Example: 1. Create your config file using the [`.env` file](example.env) as a template and save it the root. ```sh +# Domain name for TLS +DOMAIN=your.own.domain.xyz # A web3 endpoint provider -WEB3_PROVIDERS=https://rpc-endoint.example1.com,https://rpc-endoint.example2.com - +CENSUS3_WEB3PROVIDERS="https://rpc-endoint.example1.com,https://rpc-endoint.example2.com" # Internal port for the service (80 and 443 are used by traefik) -PORT=7788 - -# Domain name for TLS -# DOMAIN=your.own.domain.xyz -DOMAIN=localhost - +CENSUS3_PORT=7788 # Log level (info, debug, warning, error) -LOGLEVEL=debug - +CENSUS3_LOGLEVEL="debug" # IPFS connect key for discovering nodes -CONNECT_KEY=yourIPFSConnectKey +# CONNECT_KEY=yourIPFSConnectKey +CENSUS3_CONNECTKEY="census3key" +# Internal data folder +CENSUS3_DATADIR="./.census3" +# Scanner cooldown duration +CENSUS3_SCANNERCOOLDOWN="20s" +# UUID admin token for protected endpoints +CENSUS3_ADMINTOKENS="UUID" +# POAP API configuration +CENSUS3_POAPAPIENDPOINT="poapAPIEndpoint" +CENSUS3_POAPAUTHTOKEN="yourPOAPAuthToken" +# Gitcoin API configuration +CENSUS3_GITCOINAPIENDPOINT="gitcoinAPIEndpoint" +CENSUS3_INITIALTOKENS="/app/initial_tokens.json" ``` 2. Run the services with `docker compose`: From 3080a57b7599b23162db67faaa72232482bdb078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Mon, 29 Jan 2024 13:55:10 +0100 Subject: [PATCH 24/35] providers comments --- scanner/providers/holders_provider.go | 30 +++++++++++- scanner/providers/web3/erc20_provider.go | 55 ++++++++++++++++++++++ scanner/providers/web3/erc721_provider.go | 56 +++++++++++++++++++++++ scanner/providers/web3/erc777_provider.go | 56 +++++++++++++++++++++++ 4 files changed, 195 insertions(+), 2 deletions(-) diff --git a/scanner/providers/holders_provider.go b/scanner/providers/holders_provider.go index 316c8b69..7ae81b55 100644 --- a/scanner/providers/holders_provider.go +++ b/scanner/providers/holders_provider.go @@ -16,6 +16,8 @@ type HolderProvider interface { // attributes values must be defined in the struct that implements this // interface before calling this method. Init(conf any) error + // SetRef sets the reference to the provider. It is used to define the + // required token information to interact with the provider. SetRef(ref any) error // SetLastBalances sets the balances of the token holders for the given // id and from point in time and store it in a snapshot. It is used to @@ -29,20 +31,44 @@ type HolderProvider interface { Close() error // IsExternal returns true if the provider is an external API. IsExternal() bool - // IsSynced returns true if the current state of the provider is synced + // IsSynced returns true if the current state of the provider is synced. It + // also receives an external ID to be used if it is required by the provider. IsSynced(id []byte) bool - // Token realated methods + // Address returns the address of the current token set in the provider Address() common.Address + // Type returns the type of the current token set in the provider Type() uint64 + // TypeName returns the type name of the current token set in the provider TypeName() string + // ChainID returns the chain ID of the current token set in the provider ChainID() uint64 + // Name returns the name of the current token set in the provider. It also + // receives an external ID to be used if it is required by the provider. Name(id []byte) (string, error) + // Symbol returns the symbol of the current token set in the provider. It + // also receives an external ID to be used if it is required by the provider. Symbol(id []byte) (string, error) + // Decimals returns the decimals of the current token set in the provider. + // It also receives an external ID to be used if it is required by the + // provider. Decimals(id []byte) (uint64, error) + // TotalSupply returns the total supply of the current token set in the + // provider. It also receives an external ID to be used if it is required + // by the provider. TotalSupply(id []byte) (*big.Int, error) + // BalanceOf returns the balance of the given address for the current token + // set in the provider. It also receives an external ID to be used if it is + // required by the provider. BalanceOf(addr common.Address, id []byte) (*big.Int, error) + // BalanceAt returns the balance of the given address for the current token + // at the given block number for the current token set in the provider. It + // also receives an external ID to be used if it is required by the provider. BalanceAt(ctx context.Context, addr common.Address, id []byte, blockNumber uint64) (*big.Int, error) + // BlockTimestamp returns the timestamp of the given block number for the + // current token set in the provider BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) + // BlockRootHash returns the root hash of the given block number for the + // current token set in the provider BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) LatestBlockNumber(ctx context.Context, id []byte) (uint64, error) CreationBlock(ctx context.Context, id []byte) (uint64, error) diff --git a/scanner/providers/web3/erc20_provider.go b/scanner/providers/web3/erc20_provider.go index 8f859ef7..6e9c1564 100644 --- a/scanner/providers/web3/erc20_provider.go +++ b/scanner/providers/web3/erc20_provider.go @@ -49,6 +49,9 @@ func (p *ERC20HolderProvider) Init(iconf any) error { return nil } +// SetRef sets the reference of the token desired to use to the provider. It +// receives a Web3ProviderRef struct with the address and chainID of the token +// to use. It connects to the endpoint and initializes the contract. func (p *ERC20HolderProvider) SetRef(iref any) error { if p.endpoints == nil { return errors.New("endpoints not defined") @@ -84,12 +87,24 @@ func (p *ERC20HolderProvider) SetRef(iref any) error { return nil } +// SetLastBalances method is not implemented for ERC20 tokens, they already +// calculate the partial balances from logs without comparing with the previous +// balances. func (p *ERC20HolderProvider) SetLastBalances(_ context.Context, _ []byte, _ map[common.Address]*big.Int, _ uint64, ) error { return nil } +// HoldersBalances returns the balances of the token holders for the current +// defined token (using SetRef method). It returns the balances of the holders +// for this token from the block number provided to the latest posible block +// number (chosen between the last block number of the network and the maximun +// number of blocks to scan). It calls to rangeOfLogs to get the logs of the +// token transfers in the range of blocks and then it iterates the logs to +// calculate the balances of the holders. It returns the balances, the number +// of new transfers, the last block scanned, if the provider is synced and an +// error if it exists. func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fromBlock uint64) ( map[common.Address]*big.Int, uint64, uint64, bool, error, ) { @@ -142,34 +157,45 @@ func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fro return balances, newTransfers, lastBlock, synced, nil } +// Close method is not implemented for ERC20 tokens. func (p *ERC20HolderProvider) Close() error { return nil } +// IsExternal returns false because the provider is not an external API. func (p *ERC20HolderProvider) IsExternal() bool { return false } +// IsSynced returns true if the current state of the provider is synced. It also +// receives an external ID but it is not used by the provider. func (p *ERC20HolderProvider) IsSynced(_ []byte) bool { return p.synced.Load() } +// Address returns the address of the current token set in the provider. func (p *ERC20HolderProvider) Address() common.Address { return p.address } +// Type returns the type of the current token set in the provider. func (p *ERC20HolderProvider) Type() uint64 { return providers.CONTRACT_TYPE_ERC20 } +// TypeName returns the type name of the current token set in the provider. func (p *ERC20HolderProvider) TypeName() string { return providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC20] } +// ChainID returns the chain ID of the current token set in the provider. func (p *ERC20HolderProvider) ChainID() uint64 { return p.chainID } +// Name returns the name of the current token set in the provider. It gets the +// name from the contract. It also receives an external ID but it is not used by +// the provider. func (p *ERC20HolderProvider) Name(_ []byte) (string, error) { var err error if p.name == "" { @@ -178,6 +204,9 @@ func (p *ERC20HolderProvider) Name(_ []byte) (string, error) { return p.name, err } +// Symbol returns the symbol of the current token set in the provider. It gets +// the symbol from the contract. It also receives an external ID but it is not +// used by the provider. func (p *ERC20HolderProvider) Symbol(_ []byte) (string, error) { var err error if p.symbol == "" { @@ -186,6 +215,9 @@ func (p *ERC20HolderProvider) Symbol(_ []byte) (string, error) { return p.symbol, err } +// Decimals returns the decimals of the current token set in the provider. It +// gets the decimals from the contract. It also receives an external ID but it +// is not used by the provider. func (p *ERC20HolderProvider) Decimals(_ []byte) (uint64, error) { if p.decimals == 0 { decimals, err := p.contract.ERC20ContractCaller.Decimals(nil) @@ -197,6 +229,9 @@ func (p *ERC20HolderProvider) Decimals(_ []byte) (uint64, error) { return p.decimals, nil } +// TotalSupply returns the total supply of the current token set in the provider. +// It gets the total supply from the contract. It also receives an external ID +// but it is not used by the provider. func (p *ERC20HolderProvider) TotalSupply(_ []byte) (*big.Int, error) { var err error if p.totalSupply == nil { @@ -205,16 +240,25 @@ func (p *ERC20HolderProvider) TotalSupply(_ []byte) (*big.Int, error) { return p.totalSupply, err } +// BalanceOf returns the balance of the given address for the current token set +// in the provider. It gets the balance from the contract. It also receives an +// external ID but it is not used by the provider. func (p *ERC20HolderProvider) BalanceOf(addr common.Address, _ []byte) (*big.Int, error) { return p.contract.ERC20ContractCaller.BalanceOf(nil, addr) } +// BalanceAt returns the balance of the given address for the current token at +// the given block number for the current token set in the provider. It gets +// the balance from the contract. It also receives an external ID but it is not +// used by the provider. func (p *ERC20HolderProvider) BalanceAt(ctx context.Context, addr common.Address, _ []byte, blockNumber uint64, ) (*big.Int, error) { return p.client.BalanceAt(ctx, addr, new(big.Int).SetUint64(blockNumber)) } +// BlockTimestamp returns the timestamp of the given block number for the +// current token set in the provider. It gets the timestamp from the client. func (p *ERC20HolderProvider) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) { internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetUint64(blockNumber)) @@ -224,6 +268,8 @@ func (p *ERC20HolderProvider) BlockTimestamp(ctx context.Context, blockNumber ui return time.Unix(int64(blockHeader.Time), 0).Format(timeLayout), nil } +// BlockRootHash returns the root hash of the given block number for the current +// token set in the provider. It gets the root hash from the client. func (p *ERC20HolderProvider) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) { internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) @@ -233,6 +279,9 @@ func (p *ERC20HolderProvider) BlockRootHash(ctx context.Context, blockNumber uin return blockHeader.Root.Bytes(), nil } +// LatestBlockNumber returns the latest block number of the current token set +// in the provider. It gets the latest block number from the client. It also +// receives an external ID but it is not used by the provider. func (p *ERC20HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) (uint64, error) { internal.GetBlockByNumberCounter.Add(1) lastBlockHeader, err := p.client.HeaderByNumber(ctx, nil) @@ -242,6 +291,11 @@ func (p *ERC20HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) ( return lastBlockHeader.Number.Uint64(), nil } +// CreationBlock returns the creation block of the current token set in the +// provider. It gets the creation block from the client. It also receives an +// external ID but it is not used by the provider. It uses the +// creationBlockInRange function to calculate the creation block in the range +// of blocks. func (p *ERC20HolderProvider) CreationBlock(ctx context.Context, _ []byte) (uint64, error) { var err error if p.creationBlock == 0 { @@ -255,6 +309,7 @@ func (p *ERC20HolderProvider) CreationBlock(ctx context.Context, _ []byte) (uint return p.creationBlock, err } +// IconURI method is not implemented for ERC20 tokens. func (p *ERC20HolderProvider) IconURI(_ []byte) (string, error) { return "", nil } diff --git a/scanner/providers/web3/erc721_provider.go b/scanner/providers/web3/erc721_provider.go index 9af4614a..9e790df0 100644 --- a/scanner/providers/web3/erc721_provider.go +++ b/scanner/providers/web3/erc721_provider.go @@ -49,6 +49,9 @@ func (p *ERC721HolderProvider) Init(iconf any) error { return nil } +// SetRef sets the reference of the token desired to use to the provider. It +// receives a Web3ProviderRef struct with the address and chainID of the token +// to use. It connects to the endpoint and initializes the contract. func (p *ERC721HolderProvider) SetRef(iref any) error { if p.endpoints == nil { return errors.New("endpoints not defined") @@ -84,12 +87,24 @@ func (p *ERC721HolderProvider) SetRef(iref any) error { return nil } +// SetLastBalances method is not implemented for ERC721 tokens, they already +// calculate the partial balances from logs without comparing with the previous +// balances. func (p *ERC721HolderProvider) SetLastBalances(_ context.Context, _ []byte, _ map[common.Address]*big.Int, _ uint64, ) error { return nil } +// HoldersBalances returns the balances of the token holders for the current +// defined token (using SetRef method). It returns the balances of the holders +// for this token from the block number provided to the latest posible block +// number (chosen between the last block number of the network and the maximun +// number of blocks to scan). It calls to rangeOfLogs to get the logs of the +// token transfers in the range of blocks and then it iterates the logs to +// calculate the balances of the holders. It returns the balances, the number +// of new transfers, the last block scanned, if the provider is synced and an +// error if it exists. func (p *ERC721HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fromBlock uint64) ( map[common.Address]*big.Int, uint64, uint64, bool, error, ) { @@ -142,34 +157,45 @@ func (p *ERC721HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fr return balances, newTransfers, lastBlock, synced, nil } +// Close method is not implemented for ERC721 tokens. func (p *ERC721HolderProvider) Close() error { return nil } +// IsExternal returns false because ERC721 tokens are not external APIs. func (p *ERC721HolderProvider) IsExternal() bool { return false } +// IsSynced returns true if the current state of the provider is synced. It also +// receives an external ID but it is not used by the provider. func (p *ERC721HolderProvider) IsSynced(_ []byte) bool { return p.synced.Load() } +// Address returns the address of the current token set in the provider. func (p *ERC721HolderProvider) Address() common.Address { return p.address } +// Type returns the type of the current token set in the provider. func (p *ERC721HolderProvider) Type() uint64 { return providers.CONTRACT_TYPE_ERC721 } +// TypeName returns the type name of the current token set in the provider. func (p *ERC721HolderProvider) TypeName() string { return providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC721] } +// ChainID returns the chain ID of the current token set in the provider. func (p *ERC721HolderProvider) ChainID() uint64 { return p.chainID } +// Name returns the name of the current token set in the provider. It also +// receives an external ID but it is not used by the provider. It calls to the +// contract to get the name. func (p *ERC721HolderProvider) Name(_ []byte) (string, error) { var err error if p.name == "" { @@ -178,6 +204,9 @@ func (p *ERC721HolderProvider) Name(_ []byte) (string, error) { return p.name, err } +// Symbol returns the symbol of the current token set in the provider. It +// also receives an external ID to be used if it is required by the provider. +// It calls to the contract to get the symbol. func (p *ERC721HolderProvider) Symbol(_ []byte) (string, error) { var err error if p.symbol == "" { @@ -186,24 +215,38 @@ func (p *ERC721HolderProvider) Symbol(_ []byte) (string, error) { return p.symbol, err } +// Decimals returns the decimals of the current token set in the provider. It +// also receives an external ID but it is not used by the provider. It calls to +// the contract to get the decimals. func (p *ERC721HolderProvider) Decimals(_ []byte) (uint64, error) { return 0, nil } +// TotalSupply method is not implemented for ERC721 tokens. func (p *ERC721HolderProvider) TotalSupply(_ []byte) (*big.Int, error) { return nil, nil } +// BalanceOf returns the balance of the given address for the current token +// set in the provider. It also receives an external ID but it is not used by +// the provider. It calls to the contract to get the balance. func (p *ERC721HolderProvider) BalanceOf(addr common.Address, _ []byte) (*big.Int, error) { return p.contract.ERC721ContractCaller.BalanceOf(nil, addr) } +// BalanceAt returns the balance of the given address for the current token at +// the given block number for the current token set in the provider. It also +// receives an external ID but it is not used by the provider. It calls to the +// contract to get the balance. func (p *ERC721HolderProvider) BalanceAt(ctx context.Context, addr common.Address, _ []byte, blockNumber uint64, ) (*big.Int, error) { return p.client.BalanceAt(ctx, addr, new(big.Int).SetUint64(blockNumber)) } +// BlockTimestamp returns the timestamp of the given block number for the +// current token set in the provider. It calls to the client to get the block +// header and then it returns the timestamp. func (p *ERC721HolderProvider) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) { internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetUint64(blockNumber)) @@ -213,6 +256,9 @@ func (p *ERC721HolderProvider) BlockTimestamp(ctx context.Context, blockNumber u return time.Unix(int64(blockHeader.Time), 0).Format(timeLayout), nil } +// BlockRootHash returns the root hash of the given block number for the current +// token set in the provider. It calls to the client to get the block header and +// then it returns the root hash. func (p *ERC721HolderProvider) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) { internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) @@ -222,6 +268,10 @@ func (p *ERC721HolderProvider) BlockRootHash(ctx context.Context, blockNumber ui return blockHeader.Root.Bytes(), nil } +// LatestBlockNumber returns the latest block number of the current token set +// in the provider. It calls to the client to get the latest block header and +// then it returns the block number. It also receives an external ID but it is +// not used by the provider. func (p *ERC721HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) (uint64, error) { internal.GetBlockByNumberCounter.Add(1) lastBlockHeader, err := p.client.HeaderByNumber(ctx, nil) @@ -231,6 +281,11 @@ func (p *ERC721HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) return lastBlockHeader.Number.Uint64(), nil } +// CreationBlock returns the creation block of the current token set in the +// provider. It gets the creation block from the client. It also receives an +// external ID but it is not used by the provider. It uses the +// creationBlockInRange function to calculate the creation block in the range +// of blocks. func (p *ERC721HolderProvider) CreationBlock(ctx context.Context, _ []byte) (uint64, error) { var err error if p.creationBlock == 0 { @@ -244,6 +299,7 @@ func (p *ERC721HolderProvider) CreationBlock(ctx context.Context, _ []byte) (uin return p.creationBlock, err } +// IconURI method is not implemented for ERC721 tokens. func (p *ERC721HolderProvider) IconURI(_ []byte) (string, error) { return "", nil } diff --git a/scanner/providers/web3/erc777_provider.go b/scanner/providers/web3/erc777_provider.go index 83635ca6..9de5a43c 100644 --- a/scanner/providers/web3/erc777_provider.go +++ b/scanner/providers/web3/erc777_provider.go @@ -49,6 +49,9 @@ func (p *ERC777HolderProvider) Init(iconf any) error { return nil } +// SetRef sets the reference of the token desired to use to the provider. It +// receives a Web3ProviderRef struct with the address and chainID of the token +// to use. It connects to the endpoint and initializes the contract. func (p *ERC777HolderProvider) SetRef(iref any) error { if p.endpoints == nil { return errors.New("endpoints not defined") @@ -84,12 +87,24 @@ func (p *ERC777HolderProvider) SetRef(iref any) error { return nil } +// SetLastBalances method is not implemented for ERC777 tokens, they already +// calculate the partial balances from logs without comparing with the previous +// balances. func (p *ERC777HolderProvider) SetLastBalances(_ context.Context, _ []byte, _ map[common.Address]*big.Int, _ uint64, ) error { return nil } +// HoldersBalances returns the balances of the token holders for the current +// defined token (using SetRef method). It returns the balances of the holders +// for this token from the block number provided to the latest posible block +// number (chosen between the last block number of the network and the maximun +// number of blocks to scan). It calls to rangeOfLogs to get the logs of the +// token transfers in the range of blocks and then it iterates the logs to +// calculate the balances of the holders. It returns the balances, the number +// of new transfers, the last block scanned, if the provider is synced and an +// error if it exists. func (p *ERC777HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fromBlock uint64) ( map[common.Address]*big.Int, uint64, uint64, bool, error, ) { @@ -141,34 +156,45 @@ func (p *ERC777HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fr return balances, newTransfers, lastBlock, synced, nil } +// Close method is not implemented for ERC777 tokens. func (p *ERC777HolderProvider) Close() error { return nil } +// IconURI method is not implemented for ERC777 tokens. func (p *ERC777HolderProvider) IsExternal() bool { return false } +// IsSynced returns true if the current state of the provider is synced. It also +// receives an external ID but it is not used by the provider. func (p *ERC777HolderProvider) IsSynced(_ []byte) bool { return p.synced.Load() } +// Address returns the address of the current token set in the provider. func (p *ERC777HolderProvider) Address() common.Address { return p.address } +// Type returns the type of the current token set in the provider. func (p *ERC777HolderProvider) Type() uint64 { return providers.CONTRACT_TYPE_ERC777 } +// TypeName returns the type name of the current token set in the provider. func (p *ERC777HolderProvider) TypeName() string { return providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC777] } +// ChainID returns the chain ID of the current token set in the provider. func (p *ERC777HolderProvider) ChainID() uint64 { return p.chainID } +// Name returns the name of the current token set in the provider. It also +// receives an external ID but it is not used by the provider. It calls to the +// contract to get the name. func (p *ERC777HolderProvider) Name(_ []byte) (string, error) { var err error if p.name == "" { @@ -177,6 +203,9 @@ func (p *ERC777HolderProvider) Name(_ []byte) (string, error) { return p.name, err } +// Symbol returns the symbol of the current token set in the provider. It +// also receives an external ID to be used if it is required by the provider. +// It calls to the contract to get the symbol. func (p *ERC777HolderProvider) Symbol(_ []byte) (string, error) { var err error if p.symbol == "" { @@ -185,24 +214,38 @@ func (p *ERC777HolderProvider) Symbol(_ []byte) (string, error) { return p.symbol, err } +// Decimals returns the decimals of the current token set in the provider. It +// also receives an external ID but it is not used by the provider. It calls to +// the contract to get the decimals. func (p *ERC777HolderProvider) Decimals(_ []byte) (uint64, error) { return 0, nil } +// IconURI method is not implemented for ERC777 tokens. func (p *ERC777HolderProvider) TotalSupply(_ []byte) (*big.Int, error) { return nil, nil } +// BalanceOf returns the balance of the given address for the current token +// set in the provider. It also receives an external ID but it is not used by +// the provider. It calls to the contract to get the balance. func (p *ERC777HolderProvider) BalanceOf(addr common.Address, _ []byte) (*big.Int, error) { return p.contract.ERC777ContractCaller.BalanceOf(nil, addr) } +// BalanceAt returns the balance of the given address for the current token at +// the given block number for the current token set in the provider. It also +// receives an external ID but it is not used by the provider. It calls to the +// contract to get the balance. func (p *ERC777HolderProvider) BalanceAt(ctx context.Context, addr common.Address, _ []byte, blockNumber uint64, ) (*big.Int, error) { return p.client.BalanceAt(ctx, addr, new(big.Int).SetUint64(blockNumber)) } +// BlockTimestamp returns the timestamp of the given block number for the +// current token set in the provider. It calls to the client to get the block +// header and then it returns the timestamp. func (p *ERC777HolderProvider) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) { internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetUint64(blockNumber)) @@ -212,6 +255,9 @@ func (p *ERC777HolderProvider) BlockTimestamp(ctx context.Context, blockNumber u return time.Unix(int64(blockHeader.Time), 0).Format(timeLayout), nil } +// BlockRootHash returns the root hash of the given block number for the current +// token set in the provider. It calls to the client to get the block header and +// then it returns the root hash. func (p *ERC777HolderProvider) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) { internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) @@ -221,6 +267,10 @@ func (p *ERC777HolderProvider) BlockRootHash(ctx context.Context, blockNumber ui return blockHeader.Root.Bytes(), nil } +// LatestBlockNumber returns the latest block number of the current token set +// in the provider. It calls to the client to get the latest block header and +// then it returns the block number. It also receives an external ID but it is +// not used by the provider. func (p *ERC777HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) (uint64, error) { internal.GetBlockByNumberCounter.Add(1) lastBlockHeader, err := p.client.HeaderByNumber(ctx, nil) @@ -230,6 +280,11 @@ func (p *ERC777HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) return lastBlockHeader.Number.Uint64(), nil } +// CreationBlock returns the creation block of the current token set in the +// provider. It gets the creation block from the client. It also receives an +// external ID but it is not used by the provider. It uses the +// creationBlockInRange function to calculate the creation block in the range +// of blocks. func (p *ERC777HolderProvider) CreationBlock(ctx context.Context, _ []byte) (uint64, error) { var err error if p.creationBlock == 0 { @@ -243,6 +298,7 @@ func (p *ERC777HolderProvider) CreationBlock(ctx context.Context, _ []byte) (uin return p.creationBlock, err } +// IconURI method is not implemented for ERC777 tokens. func (p *ERC777HolderProvider) IconURI(_ []byte) (string, error) { return "", nil } From 9c967d993434236f2ebfc36d3273a2ed83a489e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Mon, 29 Jan 2024 14:01:59 +0100 Subject: [PATCH 25/35] more comments --- scanner/providers/web3/web3_provider.go | 4 ++++ scanner/scanner.go | 15 +++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/scanner/providers/web3/web3_provider.go b/scanner/providers/web3/web3_provider.go index ccd6b38a..66d9ca5a 100644 --- a/scanner/providers/web3/web3_provider.go +++ b/scanner/providers/web3/web3_provider.go @@ -131,6 +131,10 @@ func rangeOfLogs(ctx context.Context, client *ethclient.Client, addr common.Addr fromBlock += blocksRange } } + // if the last block scanned is the same as the last block of the range, + // the scan is completed and the token is synced. If not, the token is not + // synced and the last block scanned is the last block of the scanned range + // plus one. synced := fromBlock >= initialLastBlock lastSyncedBlock := initialLastBlock if !synced { diff --git a/scanner/scanner.go b/scanner/scanner.go index b44d6afe..664c4353 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -318,6 +318,7 @@ func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) ( if err != nil { return nil, 0, token.LastBlock, token.Synced, err } + // set the current holders into the provider and get the new ones currentHolders := map[common.Address]*big.Int{} for _, result := range results { bBalance, ok := new(big.Int).SetString(result.Balance, 10) @@ -420,7 +421,7 @@ func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, return tx.Commit() } // create, update or delete token holders - created, updated, deleted := 0, 0, 0 + created, updated := 0, 0 for addr, balance := range holders { // get the current token holder from the database currentTokenHolder, err := qtx.GetTokenHolder(ctx, queries.GetTokenHolderParams{ @@ -448,14 +449,17 @@ func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, created++ continue } - // compute the new balance of the holder + // parse the current balance of the holder currentBalance, ok := new(big.Int).SetString(currentTokenHolder.Balance, 10) if !ok { return fmt.Errorf("error parsing current token holder balance") } + // calculate the new balance of the holder by adding the current balance + // and the new balance newBalance := new(big.Int).Add(currentBalance, balance) - // if the calculated balance is not 0 or less and it is different - // from the current one, update it in the database + // update the token holder in the database with the new balance. + // WANING: the balance could be negative so you must filter the holders + // with negative balances to get the correct holders from the database. _, err = qtx.UpdateTokenHolderBalance(ctx, queries.UpdateTokenHolderBalanceParams{ TokenID: token.Address.Bytes(), ChainID: token.ChainID, @@ -481,7 +485,6 @@ func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, "block", token.LastBlock, "synced", token.Synced, "created", created, - "updated", updated, - "deleted", deleted) + "updated", updated) return nil } From 255d4473d868880c5f37a830dc2d61061f971b9f Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Wed, 31 Jan 2024 09:29:29 +0100 Subject: [PATCH 26/35] keep available networks latest block numbers updated in background to reduce web3 calls --- scanner/const.go | 1 + scanner/providers/gitcoin/gitcoin_provider.go | 3 + scanner/providers/holders_provider.go | 5 + scanner/providers/poap/poap_provider.go | 3 + scanner/providers/web3/erc20_provider.go | 41 ++++--- scanner/providers/web3/erc721_provider.go | 41 ++++--- scanner/providers/web3/erc777_provider.go | 41 ++++--- scanner/scanner.go | 108 +++++++++++++----- 8 files changed, 175 insertions(+), 68 deletions(-) diff --git a/scanner/const.go b/scanner/const.go index 75f46e1a..77212c8b 100644 --- a/scanner/const.go +++ b/scanner/const.go @@ -11,4 +11,5 @@ const ( snapshotBlocks = 100000 // a snapshot and reset of the tree is performed every snapshotBlocks scanSleepTime = time.Second * 20 // time to sleep between scans scanSleepTimeOnceSync = time.Second * 120 // time to sleep between scans, once all the tokens are synced + blockNumbersCooldown = 5 * time.Minute // time to wait to update latest block numbers of every supported networkd ) diff --git a/scanner/providers/gitcoin/gitcoin_provider.go b/scanner/providers/gitcoin/gitcoin_provider.go index 738f2ec8..2ba35b7e 100644 --- a/scanner/providers/gitcoin/gitcoin_provider.go +++ b/scanner/providers/gitcoin/gitcoin_provider.go @@ -92,6 +92,9 @@ func (g *GitcoinPassport) SetRef(_ any) error { return nil } +// SetLastBlockNumber is not implemented for Gitcoin Passport. +func (g *GitcoinPassport) SetLastBlockNumber(_ uint64) {} + // SetLastBalances stores the balances of the last block (or other kind of // reference). It is used to calculate the partial balances of the current // block. diff --git a/scanner/providers/holders_provider.go b/scanner/providers/holders_provider.go index 7ae81b55..73e0f503 100644 --- a/scanner/providers/holders_provider.go +++ b/scanner/providers/holders_provider.go @@ -24,6 +24,11 @@ type HolderProvider interface { // calculate the delta balances in the next call to HoldersBalances from // the given from point in time. SetLastBalances(ctx context.Context, id []byte, balances map[common.Address]*big.Int, from uint64) error + // SetLastBlockNumber sets the last block number of the token set in the + // provider. It is used to calculate the delta balances in the next call + // to HoldersBalances from the given from point in time. It helps to avoid + // GetBlockNumber calls to the provider. + SetLastBlockNumber(blockNumber uint64) // HoldersBalances returns the balances of the token holders for the given // id and delta point in time, from the stored last snapshot. HoldersBalances(ctx context.Context, id []byte, to uint64) (map[common.Address]*big.Int, uint64, uint64, bool, error) diff --git a/scanner/providers/poap/poap_provider.go b/scanner/providers/poap/poap_provider.go index a4fbc78b..69fda640 100644 --- a/scanner/providers/poap/poap_provider.go +++ b/scanner/providers/poap/poap_provider.go @@ -101,6 +101,9 @@ func (p *POAPHolderProvider) SetRef(_ any) error { return nil } +// SetLastBlockNumber method is not implemented in the POAP external provider. +func (p *POAPHolderProvider) SetLastBlockNumber(_ uint64) {} + // SetLastBalances sets the balances of the token holders for the given id and // from point in time and store it in a snapshot. func (p *POAPHolderProvider) SetLastBalances(_ context.Context, id []byte, diff --git a/scanner/providers/web3/erc20_provider.go b/scanner/providers/web3/erc20_provider.go index 6e9c1564..1a7e4c99 100644 --- a/scanner/providers/web3/erc20_provider.go +++ b/scanner/providers/web3/erc20_provider.go @@ -20,15 +20,16 @@ type ERC20HolderProvider struct { endpoints NetworkEndpoints client *ethclient.Client - contract *erc20.ERC20Contract - address common.Address - chainID uint64 - name string - symbol string - decimals uint64 - totalSupply *big.Int - creationBlock uint64 - synced atomic.Bool + contract *erc20.ERC20Contract + address common.Address + chainID uint64 + name string + symbol string + decimals uint64 + totalSupply *big.Int + creationBlock uint64 + lastNetworkBlock uint64 + synced atomic.Bool } func (p *ERC20HolderProvider) Init(iconf any) error { @@ -83,6 +84,7 @@ func (p *ERC20HolderProvider) SetRef(iref any) error { p.decimals = 0 p.totalSupply = nil p.creationBlock = 0 + p.lastNetworkBlock = 0 p.synced.Store(false) return nil } @@ -96,6 +98,14 @@ func (p *ERC20HolderProvider) SetLastBalances(_ context.Context, _ []byte, return nil } +// SetLastBlockNumber sets the last block number of the token set in the +// provider. It is used to calculate the delta balances in the next call to +// HoldersBalances from the given from point in time. It helps to avoid +// GetBlockNumber calls to the provider. +func (p *ERC20HolderProvider) SetLastBlockNumber(blockNumber uint64) { + p.lastNetworkBlock = blockNumber +} + // HoldersBalances returns the balances of the token holders for the current // defined token (using SetRef method). It returns the balances of the holders // for this token from the block number provided to the latest posible block @@ -109,10 +119,15 @@ func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fro map[common.Address]*big.Int, uint64, uint64, bool, error, ) { // calculate the range of blocks to scan, by default take the last block - // scanned and scan to the latest block - toBlock, err := p.LatestBlockNumber(ctx, nil) - if err != nil { - return nil, 0, fromBlock, false, err + // scanned and scan to the latest block, calculate the latest block if the + // current last network block is not defined + toBlock := p.lastNetworkBlock + if toBlock == 0 { + var err error + toBlock, err = p.LatestBlockNumber(ctx, nil) + if err != nil { + return nil, 0, fromBlock, false, err + } } log.Infow("scan iteration", "address", p.address, diff --git a/scanner/providers/web3/erc721_provider.go b/scanner/providers/web3/erc721_provider.go index 9e790df0..f037c0b0 100644 --- a/scanner/providers/web3/erc721_provider.go +++ b/scanner/providers/web3/erc721_provider.go @@ -20,15 +20,16 @@ type ERC721HolderProvider struct { endpoints NetworkEndpoints client *ethclient.Client - contract *erc721.ERC721Contract - address common.Address - chainID uint64 - name string - symbol string - decimals uint64 - totalSupply *big.Int - creationBlock uint64 - synced atomic.Bool + contract *erc721.ERC721Contract + address common.Address + chainID uint64 + name string + symbol string + decimals uint64 + totalSupply *big.Int + creationBlock uint64 + lastNetworkBlock uint64 + synced atomic.Bool } func (p *ERC721HolderProvider) Init(iconf any) error { @@ -83,6 +84,7 @@ func (p *ERC721HolderProvider) SetRef(iref any) error { p.decimals = 0 p.totalSupply = nil p.creationBlock = 0 + p.lastNetworkBlock = 0 p.synced.Store(false) return nil } @@ -96,6 +98,14 @@ func (p *ERC721HolderProvider) SetLastBalances(_ context.Context, _ []byte, return nil } +// SetLastBlockNumber sets the last block number of the token set in the +// provider. It is used to calculate the delta balances in the next call to +// HoldersBalances from the given from point in time. It helps to avoid +// GetBlockNumber calls to the provider. +func (p *ERC721HolderProvider) SetLastBlockNumber(blockNumber uint64) { + p.lastNetworkBlock = blockNumber +} + // HoldersBalances returns the balances of the token holders for the current // defined token (using SetRef method). It returns the balances of the holders // for this token from the block number provided to the latest posible block @@ -109,10 +119,15 @@ func (p *ERC721HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fr map[common.Address]*big.Int, uint64, uint64, bool, error, ) { // calculate the range of blocks to scan, by default take the last block - // scanned and scan to the latest block - toBlock, err := p.LatestBlockNumber(ctx, nil) - if err != nil { - return nil, 0, fromBlock, false, err + // scanned and scan to the latest block, calculate the latest block if the + // current last network block is not defined + toBlock := p.lastNetworkBlock + if toBlock == 0 { + var err error + toBlock, err = p.LatestBlockNumber(ctx, nil) + if err != nil { + return nil, 0, fromBlock, false, err + } } log.Infow("scan iteration", "address", p.address, diff --git a/scanner/providers/web3/erc777_provider.go b/scanner/providers/web3/erc777_provider.go index 9de5a43c..edd382e1 100644 --- a/scanner/providers/web3/erc777_provider.go +++ b/scanner/providers/web3/erc777_provider.go @@ -20,15 +20,16 @@ type ERC777HolderProvider struct { endpoints NetworkEndpoints client *ethclient.Client - contract *erc777.ERC777Contract - address common.Address - chainID uint64 - name string - symbol string - decimals uint64 - totalSupply *big.Int - creationBlock uint64 - synced atomic.Bool + contract *erc777.ERC777Contract + address common.Address + chainID uint64 + name string + symbol string + decimals uint64 + totalSupply *big.Int + creationBlock uint64 + lastNetworkBlock uint64 + synced atomic.Bool } func (p *ERC777HolderProvider) Init(iconf any) error { @@ -83,6 +84,7 @@ func (p *ERC777HolderProvider) SetRef(iref any) error { p.decimals = 0 p.totalSupply = nil p.creationBlock = 0 + p.lastNetworkBlock = 0 p.synced.Store(false) return nil } @@ -96,6 +98,14 @@ func (p *ERC777HolderProvider) SetLastBalances(_ context.Context, _ []byte, return nil } +// SetLastBlockNumber sets the last block number of the token set in the +// provider. It is used to calculate the delta balances in the next call to +// HoldersBalances from the given from point in time. It helps to avoid +// GetBlockNumber calls to the provider. +func (p *ERC777HolderProvider) SetLastBlockNumber(blockNumber uint64) { + p.lastNetworkBlock = blockNumber +} + // HoldersBalances returns the balances of the token holders for the current // defined token (using SetRef method). It returns the balances of the holders // for this token from the block number provided to the latest posible block @@ -109,10 +119,15 @@ func (p *ERC777HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fr map[common.Address]*big.Int, uint64, uint64, bool, error, ) { // calculate the range of blocks to scan, by default take the last block - // scanned and scan to the latest block - toBlock, err := p.LatestBlockNumber(ctx, nil) - if err != nil { - return nil, 0, fromBlock, false, err + // scanned and scan to the latest block, calculate the latest block if the + // current last network block is not defined + toBlock := p.lastNetworkBlock + if toBlock == 0 { + var err error + toBlock, err = p.LatestBlockNumber(ctx, nil) + if err != nil { + return nil, 0, fromBlock, false, err + } } log.Infow("scan iteration", "address", p.address, diff --git a/scanner/scanner.go b/scanner/scanner.go index 664c4353..002c6403 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -44,22 +44,26 @@ type Scanner struct { providers map[uint64]providers.HolderProvider coolDown time.Duration - tokens []*ScannerToken - tokensMtx sync.Mutex - waiter sync.WaitGroup + tokens []*ScannerToken + tokensMtx sync.Mutex + waiter sync.WaitGroup + latestBlockNumbers sync.Map + lastUpdatedBlockNumbers time.Time } // NewScanner returns a new scanner instance with the required parameters // initialized. func NewScanner(db *db.DB, networks web3.NetworkEndpoints, coolDown time.Duration) *Scanner { return &Scanner{ - db: db, - networks: networks, - providers: make(map[uint64]providers.HolderProvider), - coolDown: coolDown, - tokens: []*ScannerToken{}, - tokensMtx: sync.Mutex{}, - waiter: sync.WaitGroup{}, + db: db, + networks: networks, + providers: make(map[uint64]providers.HolderProvider), + coolDown: coolDown, + tokens: []*ScannerToken{}, + tokensMtx: sync.Mutex{}, + waiter: sync.WaitGroup{}, + latestBlockNumbers: sync.Map{}, + lastUpdatedBlockNumbers: time.Time{}, } } @@ -95,6 +99,13 @@ func (s *Scanner) SetProviders(newProviders ...providers.HolderProvider) error { func (s *Scanner) Start(ctx context.Context) { s.ctx, s.cancel = context.WithCancel(ctx) itCounter := 0 + // keep the latest block numbers updated + s.waiter.Add(1) + go func() { + defer s.waiter.Done() + s.getLatestBlockNumbersUpdates() + }() + // start the scanner loop for { select { case <-ctx.Done(): @@ -134,8 +145,8 @@ func (s *Scanner) Start(ctx context.Context) { log.Infow("scan iteration finished", "iteration", itCounter, "duration", time.Since(startTime).Seconds(), - "atSync", atSyncGlobal) - log.Debugf("GetBlockByNumberCounter: %d", internal.GetBlockByNumberCounter.Load()) + "atSync", atSyncGlobal, + "GetBlockByNumberCounter", internal.GetBlockByNumberCounter.Load()) if atSyncGlobal { time.Sleep(s.coolDown) } else { @@ -192,20 +203,29 @@ func (s *Scanner) TokensToScan(ctx context.Context) ([]*ScannerToken, error) { // if there are old not synced tokens, sort them by nearest to be synced // and parse them, if not, continue to avoid web3 calls if len(oldNotSyncedTokens) > 0 { - // get the current block number of every chain - currentBlockNumbers, err := s.networks.CurrentBlockNumbers(internalCtx) - if err != nil { - return nil, err - } // sort old not synced tokens by nearest to be synced, that is, the tokens // that have the minimum difference between the current block of its chain // and the last block scanned by the scanner (retrieved from the database // as LastBlock) sort.Slice(oldNotSyncedTokens, func(i, j int) bool { - iBlocksReamining := currentBlockNumbers[oldNotSyncedTokens[i].ChainID] - - uint64(oldNotSyncedTokens[i].LastBlock) - jBlocksReamining := currentBlockNumbers[oldNotSyncedTokens[j].ChainID] - - uint64(oldNotSyncedTokens[j].LastBlock) + iRawLastBlock, ok := s.latestBlockNumbers.Load(oldNotSyncedTokens[i].ChainID) + if !ok { + return false + } + iLastBlock, ok := iRawLastBlock.(uint64) + if !ok { + return false + } + jRawLastBlock, ok := s.latestBlockNumbers.Load(oldNotSyncedTokens[j].ChainID) + if !ok { + return false + } + jLastBlock, ok := jRawLastBlock.(uint64) + if !ok { + return false + } + iBlocksReamining := iLastBlock - uint64(oldNotSyncedTokens[i].LastBlock) + jBlocksReamining := jLastBlock - uint64(oldNotSyncedTokens[j].LastBlock) return iBlocksReamining < jBlocksReamining }) // parse old not synced token addresses @@ -251,11 +271,6 @@ func (s *Scanner) TokensToScan(ctx context.Context) ([]*ScannerToken, error) { func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) ( map[common.Address]*big.Int, uint64, uint64, bool, error, ) { - log.Infow("scanning holders", - "address", token.Address.Hex(), - "chainID", token.ChainID, - "externalID", token.ExternalID, - "lastBlock", token.LastBlock) internalCtx, cancel := context.WithTimeout(ctx, SCAN_TIMEOUT) defer cancel() // get the correct token holder for the current token @@ -282,6 +297,11 @@ func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) ( }); err != nil { return nil, 0, token.LastBlock, token.Synced, err } + if iLastNetworkBlock, ok := s.latestBlockNumbers.Load(token.ChainID); ok { + if lastNetworkBlock, ok := iLastNetworkBlock.(uint64); ok { + provider.SetLastBlockNumber(lastNetworkBlock) + } + } // if the token is not ready yet (its creation block has not been // calculated yet), calculate it, update the token information and // return @@ -304,10 +324,14 @@ func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) ( if err != nil { return nil, 0, token.LastBlock, token.Synced, err } - // close the database tx and commit it - return nil, 0, creationBlock, token.Synced, tx.Commit() + token.LastBlock = creationBlock } } + log.Infow("scanning holders", + "address", token.Address.Hex(), + "chainID", token.ChainID, + "externalID", token.ExternalID, + "lastBlock", token.LastBlock) // get the current token holders from the database results, err := qtx.ListTokenHolders(internalCtx, queries.ListTokenHoldersParams{ @@ -357,7 +381,7 @@ func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, holders map[common.Address]*big.Int, newTransfers, lastBlock uint64, synced bool, ) error { - log.Debugw("saving token status and holders", + log.Infow("saving token status and holders", "token", token.Address.Hex(), "chainID", token.ChainID, "externalID", token.ExternalID, @@ -488,3 +512,29 @@ func (s *Scanner) SaveHolders(ctx context.Context, token *ScannerToken, "updated", updated) return nil } + +// getLatestBlockNumbersUpdates gets the latest block numbers of every chain +// and stores them in the scanner. It is executed in a goroutine and it is +// executed every blockNumbersCooldown. It is used to avoid overloading the +// providers with requests to get the latest block number. +func (s *Scanner) getLatestBlockNumbersUpdates() { + for { + select { + case <-s.ctx.Done(): + return + default: + if time.Since(s.lastUpdatedBlockNumbers) > blockNumbersCooldown { + log.Info("getting latest block numbers") + latestBlockNumbers, err := s.networks.CurrentBlockNumbers(s.ctx) + if err != nil { + log.Error(err) + continue + } + for chainID, blockNumber := range latestBlockNumbers { + s.latestBlockNumbers.Store(chainID, blockNumber) + } + s.lastUpdatedBlockNumbers = time.Now() + } + } + } +} From 4d9d1618a53048af8df0c86db4f3cb4066914e10 Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Wed, 31 Jan 2024 12:35:39 +0100 Subject: [PATCH 27/35] document with the components definition and relations --- COMPONENTS.md | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 COMPONENTS.md diff --git a/COMPONENTS.md b/COMPONENTS.md new file mode 100644 index 00000000..072234ba --- /dev/null +++ b/COMPONENTS.md @@ -0,0 +1,57 @@ +# Census3 Service documentation + +## Index + +1. [SQLite Database](#sqlite-database) +2. [Scanner](#scanner) + 1. [Holders providers](#holders-providers) +3. [API](#api) + 1. [Toolbox](#toolbox) + +--- + +### SQLite Database +Contains all the service data. It contains six tables: +* *Tokens*: Contains the addresses, chainIDs and other attributes of the registered tokens in the service. +* *TokenTypes*: The relationship between the token type ID's and their names. It does not define the supported types, this is done by the scanner. +* *Strategies*: The list of strategies to create counts using the registered tokens. +* *Strategy Tokens*: The details of the tokens used in each strategy (such as the minimum balance required). +* *Censuses*: The list of censuses created. +* *Token Holders*: The list of addresses involved in the transfer of registered tokens. + +Check out [`./db`](./db/) folder. + +### Scanner +This component iterates until the service stops, keeping the holders and balances of each registered token updated. To do this, it performs the following steps: +1. Retrieves the token information from the database, trying to scan the new and smaller tokens first. +2. Depending on the type of token, it selects its owner provider and obtains the latest updates. +1. If the creation block of the token contract has not yet been calculated, the scanner will calculate it before updating its token holders. +3. Updates the token and its holder information in the database. +4. Loop forever. + +Check out [`./scanner`](./scanner) folder. + +#### Holders Providers +These components are defined by an interface that supports the creation of different types of holder providers, such as Web3 based (ERC20, ERC721, ERC777) or external service based (POAP or Gitcoin Passport). + +This interface defines all the methods the scanner needs to work, and retains the logic of how the holder and balance updates are calculated. + +See some examples in the [`./scanner/providers`](./scanner/providers) folder. + +### API +The API has two goals: +* Provide information: It exposes the token information, the results of the scanner and the built strategies and censuses. +* Create resources: It allows to the user to register new tokens, create new strategies or build new censuses. + +Check out [`./api`](./api) folder and the [API specification](./api/README.md). + +#### Toolbox +It includes the following packages: +* **[`internal/lexer`](./internal/lexer/)**: The lexer package helps to analyse the predicate of strategies, allowing to define a syntax to combine the token holders of a group of tokens. +* **[`internal/queue`](./internal/queue/)**: The queue package allows to the API and other components of the Census3 service to run processes in the background, providing a way to know the status of a job or retrieve its results. +* **[`internal/roundedcensus`](./internal/roundedcensus/)**: The roundedcensus package provides an algorithm to anonymize participant balances in a token based census while maintaining a certain level of accuracy. +* **[`internal/strategyoperators`](./internal/strategyoperators/)**: This package defines the differents operators to be used in the strategies, and how they combine the holders of different tokens. + + +## Schema +![Components](https://i.postimg.cc/7LYXtDcF/census3-schema.png) \ No newline at end of file From 6966330cbe801b00e710803e4bbdad903cd354cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Thu, 1 Feb 2024 09:17:43 +0100 Subject: [PATCH 28/35] last comments and small changes --- api/api.go | 2 +- api/tokens.go | 6 +- scanner/const.go | 1 + scanner/providers/gitcoin/gitcoin_provider.go | 2 +- scanner/providers/helpers_test.go | 76 +++++++++++++++++++ scanner/providers/holders_provider.go | 6 ++ scanner/providers/poap/poap_provider.go | 2 +- scanner/providers/types.go | 22 +++++- scanner/providers/web3/erc20_provider.go | 4 +- scanner/providers/web3/erc721_provider.go | 4 +- scanner/providers/web3/erc777_provider.go | 4 +- scanner/providers/web3/web3_provider.go | 10 --- scanner/scanner.go | 27 +++++-- 13 files changed, 136 insertions(+), 30 deletions(-) create mode 100644 scanner/providers/helpers_test.go diff --git a/api/api.go b/api/api.go index c8b5dc55..679b51f1 100644 --- a/api/api.go +++ b/api/api.go @@ -211,7 +211,7 @@ func (capi *census3API) CreateInitialTokens(tokensPath string) error { Decimals: token.Decimals, TotalSupply: annotations.BigInt(token.TotalSupply), CreationBlock: 0, - TypeID: uint64(web3.TokenTypeFromString(token.Type)), + TypeID: providers.TokenTypeID(token.Type), Synced: false, Tags: token.Tags, ChainID: token.ChainID, diff --git a/api/tokens.go b/api/tokens.go index 034438e4..b00c2a6e 100644 --- a/api/tokens.go +++ b/api/tokens.go @@ -114,7 +114,7 @@ func (capi *census3API) getTokens(msg *api.APIdata, ctx *httprouter.HTTPContext) for _, tokenData := range rows { tokensResponse.Tokens = append(tokensResponse.Tokens, GetTokensItemResponse{ ID: common.BytesToAddress(tokenData.ID).String(), - Type: providers.TokenTypeStringMap[tokenData.TypeID], + Type: providers.TokenTypeName(tokenData.TypeID), Decimals: tokenData.Decimals, Name: tokenData.Name, StartBlock: uint64(tokenData.CreationBlock), @@ -225,7 +225,7 @@ func (capi *census3API) createToken(msg *api.APIdata, ctx *httprouter.HTTPContex internalCtx, cancel := context.WithTimeout(ctx.Request.Context(), createTokenTimeout) defer cancel() // get the correct holder provider for the token type - tokenType := web3.TokenTypeFromString(req.Type) + tokenType := providers.TokenTypeID(req.Type) provider, exists := capi.holderProviders[tokenType] if !exists { return ErrCantCreateCensus.With("token type not supported") @@ -507,7 +507,7 @@ func (capi *census3API) getToken(msg *api.APIdata, ctx *httprouter.HTTPContext) // build response tokenResponse := GetTokenResponse{ ID: address.String(), - Type: providers.TokenTypeStringMap[tokenData.TypeID], + Type: providers.TokenTypeName(tokenData.TypeID), Decimals: tokenData.Decimals, Size: uint64(holders), Name: tokenData.Name, diff --git a/scanner/const.go b/scanner/const.go index 77212c8b..828263a4 100644 --- a/scanner/const.go +++ b/scanner/const.go @@ -3,6 +3,7 @@ package scanner import "time" const ( + READ_TIMEOUT = time.Minute SCAN_TIMEOUT = 5 * time.Minute SAVE_TIMEOUT = time.Minute ) diff --git a/scanner/providers/gitcoin/gitcoin_provider.go b/scanner/providers/gitcoin/gitcoin_provider.go index 2ba35b7e..d56badad 100644 --- a/scanner/providers/gitcoin/gitcoin_provider.go +++ b/scanner/providers/gitcoin/gitcoin_provider.go @@ -259,7 +259,7 @@ func (g *GitcoinPassport) Type() uint64 { // TypeName returns the type name of the Gitcoin Passport contract. func (g *GitcoinPassport) TypeName() string { - return providers.TokenTypeStringMap[providers.CONTRACT_TYPE_GITCOIN] + return providers.TokenTypeName(providers.CONTRACT_TYPE_GITCOIN) } // ChainID returns the chain ID of the Gitcoin Passport contract. diff --git a/scanner/providers/helpers_test.go b/scanner/providers/helpers_test.go new file mode 100644 index 00000000..00f5789a --- /dev/null +++ b/scanner/providers/helpers_test.go @@ -0,0 +1,76 @@ +package providers + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + qt "github.com/frankban/quicktest" +) + +func TestCalcPartialHolders(t *testing.T) { + c := qt.New(t) + currentHolders := map[common.Address]*big.Int{ + common.HexToAddress("0x1"): big.NewInt(100), + common.HexToAddress("0x2"): big.NewInt(200), + common.HexToAddress("0x3"): big.NewInt(300), + common.HexToAddress("0x4"): big.NewInt(400), + common.HexToAddress("0x5"): big.NewInt(500), + } + newHolders := map[common.Address]*big.Int{ + common.HexToAddress("0x1"): big.NewInt(200), + common.HexToAddress("0x2"): big.NewInt(100), + common.HexToAddress("0x3"): big.NewInt(300), + common.HexToAddress("0x6"): big.NewInt(600), + common.HexToAddress("0x7"): big.NewInt(700), + } + expectedPartialHolders := map[common.Address]*big.Int{ + common.HexToAddress("0x1"): big.NewInt(100), + common.HexToAddress("0x2"): big.NewInt(-100), + common.HexToAddress("0x4"): big.NewInt(-400), + common.HexToAddress("0x5"): big.NewInt(-500), + common.HexToAddress("0x6"): big.NewInt(600), + common.HexToAddress("0x7"): big.NewInt(700), + } + partialHolders := CalcPartialHolders(currentHolders, newHolders) + c.Assert(len(partialHolders), qt.Equals, len(expectedPartialHolders)) + for addr, balance := range partialHolders { + expectedBalance, ok := expectedPartialHolders[addr] + c.Assert(ok, qt.Equals, true) + c.Assert(balance.String(), qt.Equals, expectedBalance.String()) + } + + newgativeHolders := CalcPartialHolders(currentHolders, nil) + c.Assert(len(newgativeHolders), qt.Equals, len(currentHolders)) + for addr, balance := range newgativeHolders { + currentBalance, ok := currentHolders[addr] + c.Assert(ok, qt.Equals, true) + c.Assert(balance.String(), qt.Equals, new(big.Int).Neg(currentBalance).String()) + } + + fullNewHolders := CalcPartialHolders(nil, newHolders) + c.Assert(len(fullNewHolders), qt.Equals, len(newHolders)) + for addr, balance := range fullNewHolders { + expectedBalance, ok := newHolders[addr] + c.Assert(ok, qt.Equals, true) + c.Assert(balance.String(), qt.Equals, expectedBalance.String()) + } + + emptyHolders := CalcPartialHolders(currentHolders, currentHolders) + c.Assert(len(emptyHolders), qt.Equals, 0) + + doubleHolders := map[common.Address]*big.Int{ + common.HexToAddress("0x1"): big.NewInt(200), + common.HexToAddress("0x2"): big.NewInt(400), + common.HexToAddress("0x3"): big.NewInt(600), + common.HexToAddress("0x4"): big.NewInt(800), + common.HexToAddress("0x5"): big.NewInt(1000), + } + sameHolders := CalcPartialHolders(currentHolders, doubleHolders) + c.Assert(len(sameHolders), qt.Equals, len(currentHolders)) + for addr, balance := range sameHolders { + currentBalance, ok := currentHolders[addr] + c.Assert(ok, qt.Equals, true) + c.Assert(balance.String(), qt.Equals, currentBalance.String()) + } +} diff --git a/scanner/providers/holders_provider.go b/scanner/providers/holders_provider.go index 73e0f503..b563b339 100644 --- a/scanner/providers/holders_provider.go +++ b/scanner/providers/holders_provider.go @@ -75,7 +75,13 @@ type HolderProvider interface { // BlockRootHash returns the root hash of the given block number for the // current token set in the provider BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) + // LatestBlockNumber returns the latest block number for the network of the + // current token set in the provider LatestBlockNumber(ctx context.Context, id []byte) (uint64, error) + // CreationBlock returns the creation block number for the contract of the + // current token set in the provider CreationBlock(ctx context.Context, id []byte) (uint64, error) + // IconURI returns the icon URI of the icon asset of the current token set + // in the provider. IconURI(id []byte) (string, error) } diff --git a/scanner/providers/poap/poap_provider.go b/scanner/providers/poap/poap_provider.go index 69fda640..276c3f1b 100644 --- a/scanner/providers/poap/poap_provider.go +++ b/scanner/providers/poap/poap_provider.go @@ -186,7 +186,7 @@ func (p *POAPHolderProvider) Type() uint64 { // TypeName returns the type name of the POAP token. By default it returns the // string "POAP". func (p *POAPHolderProvider) TypeName() string { - return providers.TokenTypeStringMap[providers.CONTRACT_TYPE_POAP] + return providers.TokenTypeName(providers.CONTRACT_TYPE_POAP) } // ChainID method is not implemented in the POAP external provider. By default 1. diff --git a/scanner/providers/types.go b/scanner/providers/types.go index c70f283b..c631b9e8 100644 --- a/scanner/providers/types.go +++ b/scanner/providers/types.go @@ -26,7 +26,7 @@ const ( CONTRACT_NAME_GITCOIN = "gitcoinpassport" ) -var TokenTypeStringMap = map[uint64]string{ +var tokenTypeStringMap = map[uint64]string{ CONTRACT_TYPE_UNKNOWN: CONTRACT_NAME_UNKNOWN, CONTRACT_TYPE_ERC20: CONTRACT_NAME_ERC20, CONTRACT_TYPE_ERC721: CONTRACT_NAME_ERC721, @@ -35,7 +35,7 @@ var TokenTypeStringMap = map[uint64]string{ CONTRACT_TYPE_GITCOIN: CONTRACT_NAME_GITCOIN, } -var TokenTypeIntMap = map[string]uint64{ +var tokenTypeIntMap = map[string]uint64{ CONTRACT_NAME_UNKNOWN: CONTRACT_TYPE_UNKNOWN, CONTRACT_NAME_ERC20: CONTRACT_TYPE_ERC20, CONTRACT_NAME_ERC721: CONTRACT_TYPE_ERC721, @@ -43,3 +43,21 @@ var TokenTypeIntMap = map[string]uint64{ CONTRACT_NAME_POAP: CONTRACT_TYPE_POAP, CONTRACT_NAME_GITCOIN: CONTRACT_TYPE_GITCOIN, } + +// TokenTypeName returns the name of the token type for the given id. If the id +// is not found, it returns CONTRACT_NAME_UNKNOWN. +func TokenTypeName(id uint64) string { + if name, ok := tokenTypeStringMap[id]; ok { + return name + } + return CONTRACT_NAME_UNKNOWN +} + +// TokenTypeID returns the id of the token type for the given name. If the name +// is not found, it returns CONTRACT_TYPE_UNKNOWN. +func TokenTypeID(name string) uint64 { + if id, ok := tokenTypeIntMap[name]; ok { + return id + } + return CONTRACT_TYPE_UNKNOWN +} diff --git a/scanner/providers/web3/erc20_provider.go b/scanner/providers/web3/erc20_provider.go index 1a7e4c99..c6fb2cab 100644 --- a/scanner/providers/web3/erc20_provider.go +++ b/scanner/providers/web3/erc20_provider.go @@ -131,7 +131,7 @@ func (p *ERC20HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fro } log.Infow("scan iteration", "address", p.address, - "type", providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC20], + "type", p.TypeName(), "from", fromBlock, "to", toBlock) // iterate scanning the logs in the range of blocks until the last block @@ -200,7 +200,7 @@ func (p *ERC20HolderProvider) Type() uint64 { // TypeName returns the type name of the current token set in the provider. func (p *ERC20HolderProvider) TypeName() string { - return providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC20] + return providers.TokenTypeName(providers.CONTRACT_TYPE_ERC20) } // ChainID returns the chain ID of the current token set in the provider. diff --git a/scanner/providers/web3/erc721_provider.go b/scanner/providers/web3/erc721_provider.go index f037c0b0..ac10da79 100644 --- a/scanner/providers/web3/erc721_provider.go +++ b/scanner/providers/web3/erc721_provider.go @@ -131,7 +131,7 @@ func (p *ERC721HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fr } log.Infow("scan iteration", "address", p.address, - "type", providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC721], + "type", p.TypeName(), "from", fromBlock, "to", toBlock) // iterate scanning the logs in the range of blocks until the last block @@ -200,7 +200,7 @@ func (p *ERC721HolderProvider) Type() uint64 { // TypeName returns the type name of the current token set in the provider. func (p *ERC721HolderProvider) TypeName() string { - return providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC721] + return providers.TokenTypeName(providers.CONTRACT_TYPE_ERC721) } // ChainID returns the chain ID of the current token set in the provider. diff --git a/scanner/providers/web3/erc777_provider.go b/scanner/providers/web3/erc777_provider.go index edd382e1..a8ddd411 100644 --- a/scanner/providers/web3/erc777_provider.go +++ b/scanner/providers/web3/erc777_provider.go @@ -131,7 +131,7 @@ func (p *ERC777HolderProvider) HoldersBalances(ctx context.Context, _ []byte, fr } log.Infow("scan iteration", "address", p.address, - "type", providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC777], + "type", p.TypeName(), "from", fromBlock, "to", toBlock) // iterate scanning the logs in the range of blocks until the last block @@ -199,7 +199,7 @@ func (p *ERC777HolderProvider) Type() uint64 { // TypeName returns the type name of the current token set in the provider. func (p *ERC777HolderProvider) TypeName() string { - return providers.TokenTypeStringMap[providers.CONTRACT_TYPE_ERC777] + return providers.TokenTypeName(providers.CONTRACT_TYPE_ERC777) } // ChainID returns the chain ID of the current token set in the provider. diff --git a/scanner/providers/web3/web3_provider.go b/scanner/providers/web3/web3_provider.go index 66d9ca5a..94e4ebcc 100644 --- a/scanner/providers/web3/web3_provider.go +++ b/scanner/providers/web3/web3_provider.go @@ -11,7 +11,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - "github.com/vocdoni/census3/scanner/providers" "go.vocdoni.io/dvote/log" ) @@ -25,15 +24,6 @@ type Web3ProviderConfig struct { Endpoints NetworkEndpoints } -// TokenTypeFromString function returns the token type ID from a string value. -// If the string is not recognized, it returns CONTRACT_TYPE_UNKNOWN. -func TokenTypeFromString(s string) uint64 { - if c, ok := providers.TokenTypeIntMap[s]; ok { - return c - } - return providers.CONTRACT_TYPE_UNKNOWN -} - // creationBlockInRange function finds the block number of a contract between // the bounds provided as start and end blocks. func creationBlockInRange(client *ethclient.Client, ctx context.Context, addr common.Address, start, end uint64) (uint64, error) { diff --git a/scanner/scanner.go b/scanner/scanner.go index 002c6403..18b4a101 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -68,12 +68,16 @@ func NewScanner(db *db.DB, networks web3.NetworkEndpoints, coolDown time.Duratio } // SetProviders sets the providers that the scanner will use to get the holders -// of the tokens. +// of the tokens. It also creates the token types in the database if they do not +// exist. It returns an error something goes wrong creating the token types in +// the database. func (s *Scanner) SetProviders(newProviders ...providers.HolderProvider) error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() // create a tx to use it in the following queries for _, provider := range newProviders { + // try to create the token type in the database, if it already exists, + // update its name to ensure that it is correct according to the type id if _, err := s.db.QueriesRW.CreateTokenType(ctx, queries.CreateTokenTypeParams{ ID: provider.Type(), TypeName: provider.TypeName(), @@ -88,6 +92,7 @@ func (s *Scanner) SetProviders(newProviders ...providers.HolderProvider) error { return err } } + // include the provider in the scanner s.providers[provider.Type()] = provider } return nil @@ -111,13 +116,16 @@ func (s *Scanner) Start(ctx context.Context) { case <-ctx.Done(): return default: + // create some variables to track the loop progress itCounter++ startTime := time.Now() + // get the tokens to scan tokens, err := s.TokensToScan(ctx) if err != nil { log.Error(err) continue } + // iterate over the tokens to scan atSyncGlobal := true for _, token := range tokens { log.Infow("scanning token", @@ -126,6 +134,7 @@ func (s *Scanner) Start(ctx context.Context) { "externalID", token.ExternalID, "lastBlock", token.LastBlock, "ready", token.Ready) + // scan the token holders, newTransfers, lastBlock, synced, err := s.ScanHolders(ctx, token) if err != nil { log.Error(err) @@ -134,6 +143,8 @@ func (s *Scanner) Start(ctx context.Context) { if !synced { atSyncGlobal = false } + // save the token holders in the database in a goroutine and + // continue with the next token s.waiter.Add(1) go func(t *ScannerToken, h map[common.Address]*big.Int, n, lb uint64, sy bool) { defer s.waiter.Done() @@ -147,6 +158,8 @@ func (s *Scanner) Start(ctx context.Context) { "duration", time.Since(startTime).Seconds(), "atSync", atSyncGlobal, "GetBlockByNumberCounter", internal.GetBlockByNumberCounter.Load()) + // if all the tokens are synced, sleep the cool down time, else, + // sleep the scan sleep time if atSyncGlobal { time.Sleep(s.coolDown) } else { @@ -157,7 +170,7 @@ func (s *Scanner) Start(ctx context.Context) { } // Stop stops the scanner. It cancels the context and waits for the scanner to -// finish. +// finish. It also closes the providers. func (s *Scanner) Stop() { s.cancel() for _, provider := range s.providers { @@ -175,10 +188,10 @@ func (s *Scanner) Stop() { // block number and the last block number of their chain. // 3. The tokens that were synced in previous iterations. func (s *Scanner) TokensToScan(ctx context.Context) ([]*ScannerToken, error) { - internalCtx, cancel := context.WithTimeout(ctx, SCAN_TIMEOUT) + internalCtx, cancel := context.WithTimeout(ctx, READ_TIMEOUT) defer cancel() tokens := []*ScannerToken{} - // get last created tokens from the database to scan them first + // get last created tokens from the database to scan them first (1) lastNotSyncedTokens, err := s.db.QueriesRO.ListLastNoSyncedTokens(internalCtx) if err != nil && !errors.Is(sql.ErrNoRows, err) { return nil, err @@ -195,7 +208,7 @@ func (s *Scanner) TokensToScan(ctx context.Context) ([]*ScannerToken, error) { Synced: token.Synced, }) } - // get old tokens from the database + // get old not synced tokens from the database (2) oldNotSyncedTokens, err := s.db.QueriesRO.ListOldNoSyncedTokens(internalCtx) if err != nil && !errors.Is(sql.ErrNoRows, err) { return nil, err @@ -241,7 +254,7 @@ func (s *Scanner) TokensToScan(ctx context.Context) ([]*ScannerToken, error) { }) } } - // get last created tokens from the database to scan them first + // get synced tokens from the database to scan them last (3) syncedTokens, err := s.db.QueriesRO.ListSyncedTokens(internalCtx) if err != nil && !errors.Is(sql.ErrNoRows, err) { return nil, err @@ -297,6 +310,8 @@ func (s *Scanner) ScanHolders(ctx context.Context, token *ScannerToken) ( }); err != nil { return nil, 0, token.LastBlock, token.Synced, err } + // set the last block number of the network in the provider getting it + // from the latest block numbers cache if iLastNetworkBlock, ok := s.latestBlockNumbers.Load(token.ChainID); ok { if lastNetworkBlock, ok := iLastNetworkBlock.(uint64); ok { provider.SetLastBlockNumber(lastNetworkBlock) From b133044018b6b8407ce184d7181b7602de0fa136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Thu, 1 Feb 2024 13:39:19 +0100 Subject: [PATCH 29/35] include a query on migration to set the last scanned block of a token according to token_holders information --- db/migrations/0003_census3.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/db/migrations/0003_census3.sql b/db/migrations/0003_census3.sql index 19b0ddf0..4fbc4e0a 100644 --- a/db/migrations/0003_census3.sql +++ b/db/migrations/0003_census3.sql @@ -40,6 +40,16 @@ UPDATE tokens SET type_id = 5 WHERE type_id = 100; ALTER TABLE tokens ADD COLUMN last_block BIGINT NOT NULL DEFAULT 0; ALTER TABLE tokens ADD COLUMN analysed_transfers BIGINT NOT NULL DEFAULT 0; +UPDATE tokens +SET last_block = COALESCE(( + SELECT MAX(block_id) + FROM token_holders + WHERE token_id = tokens.id + AND chain_id = tokens.chain_id + AND external_id = tokens.external_id +), 0); + + -- List of changes: -- * Remove all token types and reset sequence -- * Recreate token types with new ids: From e8efebe2f2c69bc4ad2abb8dbd73d50e5941e6c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Fri, 2 Feb 2024 13:43:28 +0100 Subject: [PATCH 30/35] resolving some comments, small bug with last block synced solved, debug vars removed --- internal/metrics.go | 4 ---- scanner/providers/gitcoin/gitcoin_provider.go | 12 ++++-------- scanner/providers/web3/endpoint.go | 2 -- scanner/providers/web3/erc20_provider.go | 4 ---- scanner/providers/web3/erc721_provider.go | 4 ---- scanner/providers/web3/erc777_provider.go | 4 ---- scanner/providers/web3/web3_provider.go | 13 +++---------- scanner/scanner.go | 4 +--- 8 files changed, 8 insertions(+), 39 deletions(-) diff --git a/internal/metrics.go b/internal/metrics.go index 1f0d8156..ffadf3e7 100644 --- a/internal/metrics.go +++ b/internal/metrics.go @@ -1,8 +1,6 @@ package internal import ( - "sync/atomic" - "github.com/VictoriaMetrics/metrics" ) @@ -30,8 +28,6 @@ var ( TotalNumberOfCensuses = metrics.NewCounter(`census3_total_number_of_censuses`) // number of censuses by type (anonymous or not) NumberOfCensusesByType = metrics.NewSet() - - GetBlockByNumberCounter = atomic.Uint64{} ) func init() { diff --git a/scanner/providers/gitcoin/gitcoin_provider.go b/scanner/providers/gitcoin/gitcoin_provider.go index d56badad..23039905 100644 --- a/scanner/providers/gitcoin/gitcoin_provider.go +++ b/scanner/providers/gitcoin/gitcoin_provider.go @@ -12,7 +12,6 @@ import ( "sync" "sync/atomic" "time" - "unsafe" "github.com/ethereum/go-ethereum/common" "github.com/vocdoni/census3/scanner/providers" @@ -80,10 +79,8 @@ func (g *GitcoinPassport) Init(iconf any) error { g.updated.Store(false) // init balances variables g.currentBalances = make(map[common.Address]*big.Int) - g.currentBalancesMtx = sync.RWMutex{} g.newBalances = make(map[common.Address]*big.Int) - g.newBalancesMtx = sync.RWMutex{} - g.lastUpdate.Store(time.Time{}) + return nil } @@ -118,9 +115,10 @@ func (g *GitcoinPassport) SetLastBalances(_ context.Context, _ []byte, func (g *GitcoinPassport) HoldersBalances(_ context.Context, _ []byte, _ uint64) ( map[common.Address]*big.Int, uint64, uint64, bool, error, ) { + // if there is no last update, set it to zero lastUpdate, ok := g.lastUpdate.Load().(time.Time) if !ok { - return nil, 1, 0, false, fmt.Errorf("error getting last update") + lastUpdate = time.Time{} } if time.Since(lastUpdate) > g.cooldown && !g.downloading.Load() { log.Info("downloading Gitcoin Passport balances") @@ -214,11 +212,9 @@ func (g *GitcoinPassport) updateBalances() error { } } } - balancesSize := unsafe.Sizeof(balances) log.Infow("Gitcoin Passport balances download finished", "elapsed", elapsed, - "holders", len(balances), - "size", balancesSize) + "holders", len(balances)) // remove duplicated addresses keeping the last one // calculate partial balances and store them g.updated.Store(true) diff --git a/scanner/providers/web3/endpoint.go b/scanner/providers/web3/endpoint.go index cd47d771..04614cfb 100644 --- a/scanner/providers/web3/endpoint.go +++ b/scanner/providers/web3/endpoint.go @@ -8,7 +8,6 @@ import ( "os" "github.com/ethereum/go-ethereum/ethclient" - "github.com/vocdoni/census3/internal" "go.vocdoni.io/dvote/log" ) @@ -115,7 +114,6 @@ func (nps NetworkEndpoints) CurrentBlockNumbers(ctx context.Context) (map[uint64 if err != nil { return blockNumbers, err } - internal.GetBlockByNumberCounter.Add(1) blockNumber, err := cli.BlockNumber(ctx) if err != nil { return blockNumbers, fmt.Errorf("error getting the block number from %s network: %w", endpoint.Name, err) diff --git a/scanner/providers/web3/erc20_provider.go b/scanner/providers/web3/erc20_provider.go index c6fb2cab..e8ecd0da 100644 --- a/scanner/providers/web3/erc20_provider.go +++ b/scanner/providers/web3/erc20_provider.go @@ -11,7 +11,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" erc20 "github.com/vocdoni/census3/contracts/erc/erc20" - "github.com/vocdoni/census3/internal" "github.com/vocdoni/census3/scanner/providers" "go.vocdoni.io/dvote/log" ) @@ -275,7 +274,6 @@ func (p *ERC20HolderProvider) BalanceAt(ctx context.Context, addr common.Address // BlockTimestamp returns the timestamp of the given block number for the // current token set in the provider. It gets the timestamp from the client. func (p *ERC20HolderProvider) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) { - internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetUint64(blockNumber)) if err != nil { return "", err @@ -286,7 +284,6 @@ func (p *ERC20HolderProvider) BlockTimestamp(ctx context.Context, blockNumber ui // BlockRootHash returns the root hash of the given block number for the current // token set in the provider. It gets the root hash from the client. func (p *ERC20HolderProvider) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) { - internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) if err != nil { return nil, err @@ -298,7 +295,6 @@ func (p *ERC20HolderProvider) BlockRootHash(ctx context.Context, blockNumber uin // in the provider. It gets the latest block number from the client. It also // receives an external ID but it is not used by the provider. func (p *ERC20HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) (uint64, error) { - internal.GetBlockByNumberCounter.Add(1) lastBlockHeader, err := p.client.HeaderByNumber(ctx, nil) if err != nil { return 0, err diff --git a/scanner/providers/web3/erc721_provider.go b/scanner/providers/web3/erc721_provider.go index ac10da79..70d08426 100644 --- a/scanner/providers/web3/erc721_provider.go +++ b/scanner/providers/web3/erc721_provider.go @@ -11,7 +11,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" erc721 "github.com/vocdoni/census3/contracts/erc/erc721" - "github.com/vocdoni/census3/internal" "github.com/vocdoni/census3/scanner/providers" "go.vocdoni.io/dvote/log" ) @@ -263,7 +262,6 @@ func (p *ERC721HolderProvider) BalanceAt(ctx context.Context, addr common.Addres // current token set in the provider. It calls to the client to get the block // header and then it returns the timestamp. func (p *ERC721HolderProvider) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) { - internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetUint64(blockNumber)) if err != nil { return "", err @@ -275,7 +273,6 @@ func (p *ERC721HolderProvider) BlockTimestamp(ctx context.Context, blockNumber u // token set in the provider. It calls to the client to get the block header and // then it returns the root hash. func (p *ERC721HolderProvider) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) { - internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) if err != nil { return nil, err @@ -288,7 +285,6 @@ func (p *ERC721HolderProvider) BlockRootHash(ctx context.Context, blockNumber ui // then it returns the block number. It also receives an external ID but it is // not used by the provider. func (p *ERC721HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) (uint64, error) { - internal.GetBlockByNumberCounter.Add(1) lastBlockHeader, err := p.client.HeaderByNumber(ctx, nil) if err != nil { return 0, err diff --git a/scanner/providers/web3/erc777_provider.go b/scanner/providers/web3/erc777_provider.go index a8ddd411..018e0bc3 100644 --- a/scanner/providers/web3/erc777_provider.go +++ b/scanner/providers/web3/erc777_provider.go @@ -11,7 +11,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" erc777 "github.com/vocdoni/census3/contracts/erc/erc777" - "github.com/vocdoni/census3/internal" "github.com/vocdoni/census3/scanner/providers" "go.vocdoni.io/dvote/log" ) @@ -262,7 +261,6 @@ func (p *ERC777HolderProvider) BalanceAt(ctx context.Context, addr common.Addres // current token set in the provider. It calls to the client to get the block // header and then it returns the timestamp. func (p *ERC777HolderProvider) BlockTimestamp(ctx context.Context, blockNumber uint64) (string, error) { - internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetUint64(blockNumber)) if err != nil { return "", err @@ -274,7 +272,6 @@ func (p *ERC777HolderProvider) BlockTimestamp(ctx context.Context, blockNumber u // token set in the provider. It calls to the client to get the block header and // then it returns the root hash. func (p *ERC777HolderProvider) BlockRootHash(ctx context.Context, blockNumber uint64) ([]byte, error) { - internal.GetBlockByNumberCounter.Add(1) blockHeader, err := p.client.HeaderByNumber(ctx, new(big.Int).SetInt64(int64(blockNumber))) if err != nil { return nil, err @@ -287,7 +284,6 @@ func (p *ERC777HolderProvider) BlockRootHash(ctx context.Context, blockNumber ui // then it returns the block number. It also receives an external ID but it is // not used by the provider. func (p *ERC777HolderProvider) LatestBlockNumber(ctx context.Context, _ []byte) (uint64, error) { - internal.GetBlockByNumberCounter.Add(1) lastBlockHeader, err := p.client.HeaderByNumber(ctx, nil) if err != nil { return 0, err diff --git a/scanner/providers/web3/web3_provider.go b/scanner/providers/web3/web3_provider.go index 94e4ebcc..cf82ba07 100644 --- a/scanner/providers/web3/web3_provider.go +++ b/scanner/providers/web3/web3_provider.go @@ -125,15 +125,8 @@ func rangeOfLogs(ctx context.Context, client *ethclient.Client, addr common.Addr // the scan is completed and the token is synced. If not, the token is not // synced and the last block scanned is the last block of the scanned range // plus one. - synced := fromBlock >= initialLastBlock - lastSyncedBlock := initialLastBlock - if !synced { - lastSyncedBlock = uint64(0) - for _, l := range finalLogs { - if l.BlockNumber > lastSyncedBlock { - lastSyncedBlock = l.BlockNumber + 1 - } - } + if fromBlock > initialLastBlock { + fromBlock = initialLastBlock } - return finalLogs, lastSyncedBlock, synced, nil + return finalLogs, fromBlock, fromBlock >= initialLastBlock, nil } diff --git a/scanner/scanner.go b/scanner/scanner.go index 18b4a101..18257736 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -14,7 +14,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/vocdoni/census3/db" queries "github.com/vocdoni/census3/db/sqlc" - "github.com/vocdoni/census3/internal" "github.com/vocdoni/census3/scanner/providers" "github.com/vocdoni/census3/scanner/providers/web3" "go.vocdoni.io/dvote/log" @@ -156,8 +155,7 @@ func (s *Scanner) Start(ctx context.Context) { log.Infow("scan iteration finished", "iteration", itCounter, "duration", time.Since(startTime).Seconds(), - "atSync", atSyncGlobal, - "GetBlockByNumberCounter", internal.GetBlockByNumberCounter.Load()) + "atSync", atSyncGlobal) // if all the tokens are synced, sleep the cool down time, else, // sleep the scan sleep time if atSyncGlobal { From 0d2c1c5195c3fb143ad6246c74005625fc51af8c Mon Sep 17 00:00:00 2001 From: p4u Date: Fri, 2 Feb 2024 15:15:24 +0100 Subject: [PATCH 31/35] add AI pull-request reviewer Signed-off-by: p4u --- .github/workflows/ai-pr-reviewer.yml | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/ai-pr-reviewer.yml diff --git a/.github/workflows/ai-pr-reviewer.yml b/.github/workflows/ai-pr-reviewer.yml new file mode 100644 index 00000000..a2168254 --- /dev/null +++ b/.github/workflows/ai-pr-reviewer.yml @@ -0,0 +1,30 @@ +name: Code Review + +permissions: + contents: read + pull-requests: write + +on: + pull_request: + pull_request_review_comment: + types: [created] + +concurrency: + group: + ${{ github.repository }}-${{ github.event.number || github.head_ref || + github.sha }}-${{ github.workflow }}-${{ github.event_name == + 'pull_request_review_comment' && 'pr_comment' || 'pr' }} + cancel-in-progress: ${{ github.event_name != 'pull_request_review_comment' }} + +jobs: + review: + runs-on: ubuntu-latest + steps: + - uses: coderabbitai/ai-pr-reviewer@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + with: + debug: false + review_simple_changes: true + review_comment_lgtm: true From 8bf73fbe4928dbd8cb125d7d425d05b15704ba44 Mon Sep 17 00:00:00 2001 From: p4u Date: Fri, 2 Feb 2024 15:21:54 +0100 Subject: [PATCH 32/35] use gpt4 model for AI pull-request reviewer Signed-off-by: p4u --- .github/workflows/ai-pr-reviewer.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ai-pr-reviewer.yml b/.github/workflows/ai-pr-reviewer.yml index a2168254..cc086640 100644 --- a/.github/workflows/ai-pr-reviewer.yml +++ b/.github/workflows/ai-pr-reviewer.yml @@ -28,3 +28,5 @@ jobs: debug: false review_simple_changes: true review_comment_lgtm: true + openai_heavy_model: gpt-4 + From 97b60a898333351d865d6b2c0ff295d9caf554bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Sat, 3 Feb 2024 14:56:32 +0100 Subject: [PATCH 33/35] merge migrations into a single file, database must be reset --- db/migrations/0001_census3.sql | 44 +++++----------------- db/migrations/0002_census3.sql | 7 ---- db/migrations/0003_census3.sql | 67 ---------------------------------- 3 files changed, 10 insertions(+), 108 deletions(-) delete mode 100644 db/migrations/0002_census3.sql delete mode 100644 db/migrations/0003_census3.sql diff --git a/db/migrations/0001_census3.sql b/db/migrations/0001_census3.sql index ec480773..9d59543b 100644 --- a/db/migrations/0001_census3.sql +++ b/db/migrations/0001_census3.sql @@ -11,12 +11,12 @@ CREATE TABLE token_types ( type_name TEXT NOT NULL UNIQUE ); -INSERT INTO token_types (type_name) VALUES ('erc20'); -INSERT INTO token_types (type_name) VALUES ('erc721'); -INSERT INTO token_types (type_name) VALUES ('erc1155'); -INSERT INTO token_types (type_name) VALUES ('erc777'); -INSERT INTO token_types (type_name) VALUES ('nation3'); -INSERT INTO token_types (type_name) VALUES ('want'); +INSERT INTO token_types (id, type_name) VALUES (0, 'unknown'); +INSERT INTO token_types (id, type_name) VALUES (1, 'erc20'); +INSERT INTO token_types (id, type_name) VALUES (2, 'erc721');; +INSERT INTO token_types (id, type_name) VALUES (3, 'erc777'); +INSERT INTO token_types (id, type_name) VALUES (4, 'poap'); +INSERT INTO token_types (id, type_name) VALUES (5, 'gitcoinpassport'); CREATE TABLE tokens ( id BLOB NOT NULL, @@ -34,6 +34,8 @@ CREATE TABLE tokens ( default_strategy INTEGER NOT NULL DEFAULT 0, icon_uri TEXT NOT NULL DEFAULT '', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + last_block BIGINT NOT NULL DEFAULT 0, + analysed_transfers BIGINT NOT NULL DEFAULT 0, PRIMARY KEY (id, chain_id, external_id), FOREIGN KEY (type_id) REFERENCES token_types(id) ON DELETE CASCADE, FOREIGN KEY (default_strategy) REFERENCES strategies(id) ON DELETE CASCADE @@ -49,21 +51,12 @@ CREATE TABLE censuses ( weight BLOB, census_type INTEGER NOT NULL, queue_id TEXT NOT NULL, + accuracy FLOAT NOT NULL DEFAULT '100.0', FOREIGN KEY (strategy_id) REFERENCES strategies(id) ON DELETE CASCADE, UNIQUE(id, merkle_root) ); CREATE INDEX idx_censuses_strategy_id ON censuses(strategy_id); -CREATE TABLE blocks ( - id INTEGER PRIMARY KEY NOT NULL, - timestamp TEXT NOT NULL UNIQUE, - root_hash BLOB NOT NULL UNIQUE -); - -CREATE TABLE holders ( - id BLOB PRIMARY KEY NOT NULL -); - CREATE TABLE token_holders ( token_id BLOB NOT NULL, holder_id BLOB NOT NULL, @@ -72,9 +65,7 @@ CREATE TABLE token_holders ( chain_id INTEGER NOT NULL, external_id TEXT NULL DEFAULT '', PRIMARY KEY (token_id, holder_id, block_id, chain_id, external_id), - FOREIGN KEY (token_id) REFERENCES tokens(id) ON DELETE CASCADE, - FOREIGN KEY (holder_id) REFERENCES holders(id) ON DELETE CASCADE, - FOREIGN KEY (block_id) REFERENCES blocks(id) ON DELETE CASCADE + FOREIGN KEY (token_id) REFERENCES tokens(id) ON DELETE CASCADE ); CREATE INDEX idx_token_holders_token_id ON token_holders(token_id); CREATE INDEX idx_token_holders_holder_id ON token_holders(holder_id); @@ -93,19 +84,7 @@ CREATE TABLE strategy_tokens ( CREATE INDEX idx_strategy_tokens_strategy_id ON strategy_tokens(strategy_id); CREATE INDEX idx_strategy_tokens_token_id ON strategy_tokens(token_id); -CREATE TABLE census_blocks ( - census_id INTEGER NOT NULL, - block_id INTEGER NOT NULL, - PRIMARY KEY (census_id, block_id), - FOREIGN KEY (census_id) REFERENCES censuses(id) ON DELETE CASCADE, - FOREIGN KEY (block_id) REFERENCES blocks(id) ON DELETE CASCADE -); -CREATE INDEX idx_census_blocks_census_id ON census_blocks(census_id); -CREATE INDEX idx_census_blocks_block_id ON census_blocks(block_id); - -- +goose Down -DROP INDEX IF EXISTS idx_census_blocks_block_id; -DROP INDEX IF EXISTS idx_census_blocks_census_id; DROP INDEX IF EXISTS idx_strategy_tokens_token_id; DROP INDEX IF EXISTS idx_strategy_tokens_strategy_id; DROP INDEX IF EXISTS idx_token_holders_block_id; @@ -114,11 +93,8 @@ DROP INDEX IF EXISTS idx_token_holders_token_id; DROP INDEX IF EXISTS idx_censuses_strategy_id; DROP INDEX IF EXISTS idx_tokens_type_id; -DROP TABLE IF EXISTS census_blocks; DROP TABLE IF EXISTS strategy_tokens; DROP TABLE IF EXISTS token_holders; -DROP TABLE IF EXISTS holders; -DROP TABLE IF EXISTS blocks; DROP TABLE IF EXISTS censuses; DROP TABLE IF EXISTS tokens; DROP TABLE IF EXISTS token_types; diff --git a/db/migrations/0002_census3.sql b/db/migrations/0002_census3.sql deleted file mode 100644 index ec724b4d..00000000 --- a/db/migrations/0002_census3.sql +++ /dev/null @@ -1,7 +0,0 @@ - --- +goose Up -ALTER TABLE censuses ADD COLUMN accuracy FLOAT NOT NULL DEFAULT '100.0'; - - --- List of changes: --- * Add 'accuracy' column to 'censuses' table \ No newline at end of file diff --git a/db/migrations/0003_census3.sql b/db/migrations/0003_census3.sql deleted file mode 100644 index 4fbc4e0a..00000000 --- a/db/migrations/0003_census3.sql +++ /dev/null @@ -1,67 +0,0 @@ - --- +goose Up - --- prepare token_holders table to delete blocks, holders and census_blocks tables -CREATE TABLE token_holders_backup ( - token_id BLOB NOT NULL, - holder_id BLOB NOT NULL, - balance TEXT NOT NULL, - block_id INTEGER NOT NULL, - chain_id INTEGER NOT NULL, - external_id TEXT NULL DEFAULT '', - PRIMARY KEY (token_id, holder_id, block_id, chain_id, external_id), - FOREIGN KEY (token_id) REFERENCES tokens(id) ON DELETE CASCADE -); - -INSERT INTO token_holders_backup SELECT * FROM token_holders; -DROP TABLE token_holders; -ALTER TABLE token_holders_backup RENAME TO token_holders; -DROP TABLE blocks; -DROP TABLE holders; -DROP TABLE census_blocks; - -DELETE FROM token_types; -UPDATE sqlite_sequence SET seq = 0 WHERE name = 'token_types'; -INSERT INTO token_types (id, type_name) VALUES (0, 'unknown'); -INSERT INTO token_types (id, type_name) VALUES (1, 'erc20'); -INSERT INTO token_types (id, type_name) VALUES (2, 'erc721');; -INSERT INTO token_types (id, type_name) VALUES (3, 'erc777'); -INSERT INTO token_types (id, type_name) VALUES (4, 'poap'); -INSERT INTO token_types (id, type_name) VALUES (5, 'gitcoinpassport'); - -DELETE FROM tokens WHERE type_id = 3; -DELETE FROM tokens WHERE type_id = 5; -DELETE FROM tokens WHERE type_id = 6; - -UPDATE tokens SET type_id = 3 WHERE type_id = 4; -UPDATE tokens SET type_id = 4 WHERE type_id = 8; -UPDATE tokens SET type_id = 5 WHERE type_id = 100; - -ALTER TABLE tokens ADD COLUMN last_block BIGINT NOT NULL DEFAULT 0; -ALTER TABLE tokens ADD COLUMN analysed_transfers BIGINT NOT NULL DEFAULT 0; - -UPDATE tokens -SET last_block = COALESCE(( - SELECT MAX(block_id) - FROM token_holders - WHERE token_id = tokens.id - AND chain_id = tokens.chain_id - AND external_id = tokens.external_id -), 0); - - --- List of changes: --- * Remove all token types and reset sequence --- * Recreate token types with new ids: --- * [new] unknown 0 --- * erc20 1 --- * erc721 2 --- * [updated] erc777 from 4 to 3 --- * [updated] poap from 8 to 4 --- * [updated] gitcoinpassport from 100 to 5 --- * [removed] erc1155 --- * [removed] nation3 --- * [removed] want --- * [removed] erc721_burned --- * Add 'last_block' column to 'tokens' table --- * Add 'analysed_transfers' column to 'tokens' table \ No newline at end of file From 8827087da6c4a5c158ef3a65e17f82904d85035c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Sat, 3 Feb 2024 14:57:21 +0100 Subject: [PATCH 34/35] limit ia comments --- .github/workflows/ai-pr-reviewer.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ai-pr-reviewer.yml b/.github/workflows/ai-pr-reviewer.yml index cc086640..5b121b83 100644 --- a/.github/workflows/ai-pr-reviewer.yml +++ b/.github/workflows/ai-pr-reviewer.yml @@ -26,7 +26,7 @@ jobs: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} with: debug: false - review_simple_changes: true - review_comment_lgtm: true + review_simple_changes: false + review_comment_lgtm: false openai_heavy_model: gpt-4 From a1a80f169b68b9ab149502ca57d6019a7fb6ff14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Men=C3=A9ndez?= Date: Sat, 3 Feb 2024 15:41:50 +0100 Subject: [PATCH 35/35] some web3 rpc providers return an error if eth_getLogs is called with a range of blocks that exceed the last block of the network, this commit includes a check to ensure that both range bounds are valid blocks --- scanner/providers/web3/web3_provider.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/scanner/providers/web3/web3_provider.go b/scanner/providers/web3/web3_provider.go index cf82ba07..5be4639d 100644 --- a/scanner/providers/web3/web3_provider.go +++ b/scanner/providers/web3/web3_provider.go @@ -64,8 +64,7 @@ func rangeOfLogs(ctx context.Context, client *ethclient.Client, addr common.Addr ) ([]types.Log, uint64, bool, error) { // if the range is too big, scan only a part of it using the constant // BLOCKS_TO_SCAN_AT_ONCE - initialLastBlock := lastBlock - if lastBlock-fromBlock > BLOCKS_TO_SCAN_AT_ONCE { + if lastBlock-fromBlock > BLOCKS_TO_SCAN_AT_ONCE && fromBlock+MAX_SCAN_BLOCKS_PER_ITERATION < lastBlock { lastBlock = fromBlock + MAX_SCAN_BLOCKS_PER_ITERATION } if fromBlock > lastBlock { @@ -88,15 +87,19 @@ func rangeOfLogs(ctx context.Context, client *ethclient.Client, addr common.Addr if logCount > MAX_SCAN_LOGS_PER_ITERATION { return finalLogs, fromBlock, false, nil } + toBlock := fromBlock + blocksRange - 1 + if toBlock > lastBlock { + toBlock = lastBlock + } log.Debugw("scanning logs", "address", addr.Hex(), "fromBlock", fromBlock, - "toBlock", fromBlock+blocksRange-1) + "toBlock", toBlock) // compose the filter to get the logs of the ERC20 Transfer events filter := ethereum.FilterQuery{ Addresses: []common.Address{addr}, FromBlock: new(big.Int).SetUint64(fromBlock), - ToBlock: new(big.Int).SetUint64(fromBlock + blocksRange - 1), + ToBlock: new(big.Int).SetUint64(toBlock), Topics: [][]common.Hash{topicHashes}, } // get the logs and check if there are any errors @@ -125,8 +128,8 @@ func rangeOfLogs(ctx context.Context, client *ethclient.Client, addr common.Addr // the scan is completed and the token is synced. If not, the token is not // synced and the last block scanned is the last block of the scanned range // plus one. - if fromBlock > initialLastBlock { - fromBlock = initialLastBlock + if fromBlock > lastBlock { + fromBlock = lastBlock } - return finalLogs, fromBlock, fromBlock >= initialLastBlock, nil + return finalLogs, fromBlock, fromBlock >= lastBlock, nil }