diff --git a/server/inject.go b/server/inject.go deleted file mode 100644 index de5a9eeef..000000000 --- a/server/inject.go +++ /dev/null @@ -1,457 +0,0 @@ -//go:build wireinject -// +build wireinject - -package server - -import ( - "context" - "database/sql" - "net/http" - - "github.com/ethereum/go-ethereum/ethclient" - "github.com/google/wire" - "github.com/jackc/pgx/v4/pgxpool" - - db "github.com/mikeydub/go-gallery/db/gen/coredb" - "github.com/mikeydub/go-gallery/service/eth" - "github.com/mikeydub/go-gallery/service/multichain" - "github.com/mikeydub/go-gallery/service/multichain/poap" - "github.com/mikeydub/go-gallery/service/multichain/simplehash" - "github.com/mikeydub/go-gallery/service/multichain/tezos" - "github.com/mikeydub/go-gallery/service/multichain/wrapper" - "github.com/mikeydub/go-gallery/service/persist" - "github.com/mikeydub/go-gallery/service/persist/postgres" - "github.com/mikeydub/go-gallery/service/redis" - "github.com/mikeydub/go-gallery/service/rpc" - "github.com/mikeydub/go-gallery/service/rpc/arweave" - "github.com/mikeydub/go-gallery/service/rpc/ipfs" - "github.com/mikeydub/go-gallery/service/task" - "github.com/mikeydub/go-gallery/service/tokenmanage" - "github.com/mikeydub/go-gallery/util" -) - -// envInit is a type returned after setting up the environment -// Adding envInit as a dependency to a provider will ensure that the environment is set up prior -// to calling the provider -type envInit struct{} - -// NewMultichainProvider is a wire injector that sets up a multichain provider instance -func NewMultichainProvider(ctx context.Context, envFunc func()) (*multichain.Provider, func()) { - wire.Build( - setEnv, - wire.Value(http.DefaultClient), // HTTP client shared between providers - postgres.NewRepositories, - dbConnSet, - wire.Struct(new(multichain.ChainProvider), "*"), - tokenProcessingSubmitterInjector, - multichainProviderInjector, - ethInjector, - tezosInjector, - optimismInjector, - poapInjector, - zoraInjector, - baseInjector, - polygonInjector, - arbitrumInjector, - ) - return nil, nil -} - -// dbConnSet is a wire provider set for initializing a postgres connection -var dbConnSet = wire.NewSet( - newPqClient, - newPgxClient, - newQueries, -) - -func setEnv(f func()) envInit { - f() - return envInit{} -} - -func newPqClient(e envInit) (*sql.DB, func()) { - pq := postgres.MustCreateClient() - return pq, func() { pq.Close() } -} - -func newPgxClient(envInit) (*pgxpool.Pool, func()) { - pgx := postgres.NewPgxClient() - return pgx, func() { pgx.Close() } -} - -func newQueries(p *pgxpool.Pool) *db.Queries { - return db.New(p) -} - -func newTokenManageCache() *redis.Cache { - return redis.NewCache(redis.TokenManageCache) -} - -func multichainProviderInjector(ctx context.Context, repos *postgres.Repositories, q *db.Queries, chainProvider *multichain.ChainProvider, submitter *tokenmanage.TokenProcessingSubmitter) *multichain.Provider { - panic(wire.Build( - wire.Struct(new(multichain.Provider), "*"), - wire.Bind(new(tokenmanage.Submitter), util.ToPointer(submitter)), - newProviderLookup, - )) -} - -// New chains must be added here -func newProviderLookup(p *multichain.ChainProvider) multichain.ProviderLookup { - return multichain.ProviderLookup{ - persist.ChainETH: p.Ethereum, - persist.ChainTezos: p.Tezos, - persist.ChainOptimism: p.Optimism, - persist.ChainArbitrum: p.Arbitrum, - persist.ChainPOAP: p.Poap, - persist.ChainZora: p.Zora, - persist.ChainBase: p.Base, - persist.ChainPolygon: p.Polygon, - } -} - -func customMetadataHandlersInjector() *multichain.CustomMetadataHandlers { - panic(wire.Build( - multichain.NewCustomMetadataHandlers, - rpc.NewEthClient, - ipfs.NewShell, - arweave.NewClient, - )) -} - -func ethInjector(envInit, context.Context, *http.Client) (*multichain.EthereumProvider, func()) { - panic(wire.Build( - rpc.NewEthClient, - wire.Value(persist.ChainETH), - ethProviderInjector, - ethSyncPipelineInjector, - ethVerifierInjector, - simplehash.NewProvider, - )) -} - -func ethVerifierInjector(ethClient *ethclient.Client) *eth.Verifier { - panic(wire.Build(wire.Struct(new(eth.Verifier), "*"))) -} - -func ethProviderInjector( - ctx context.Context, - syncPipeline *wrapper.SyncPipelineWrapper, - verifier *eth.Verifier, - simplehashProvider *simplehash.Provider, -) *multichain.EthereumProvider { - panic(wire.Build( - wire.Struct(new(multichain.EthereumProvider), "*"), - wire.Bind(new(multichain.ContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokenMetadataBatcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokenMetadataFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensByContractWalletFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensByTokenIdentifiersFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensIncrementalContractFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.Verifier), util.ToPointer(verifier)), - )) -} - -func ethSyncPipelineInjector( - ctx context.Context, - httpClient *http.Client, - chain persist.Chain, - simplehashProvider *simplehash.Provider, -) (*wrapper.SyncPipelineWrapper, func()) { - panic(wire.Build( - wire.Struct(new(wrapper.SyncPipelineWrapper), "*"), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), - customMetadataHandlersInjector, - )) -} - -func tezosInjector(envInit, *http.Client) *multichain.TezosProvider { - wire.Build( - tezosProviderInjector, - wire.Value(persist.ChainTezos), - tezos.NewProvider, - simplehash.NewProvider, - ) - return nil -} - -func tezosProviderInjector(tezosProvider *tezos.Provider, simplehashProvider *simplehash.Provider) *multichain.TezosProvider { - panic(wire.Build( - wire.Struct(new(multichain.TezosProvider), "*"), - wire.Bind(new(multichain.Verifier), util.ToPointer(tezosProvider)), - wire.Bind(new(multichain.ContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenMetadataFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), - )) -} - -func optimismInjector(context.Context, *http.Client) (*multichain.OptimismProvider, func()) { - panic(wire.Build( - wire.Value(persist.ChainOptimism), - simplehash.NewProvider, - optimismProviderInjector, - optimismSyncPipelineInjector, - )) -} - -func optimismProviderInjector( - syncPipeline *wrapper.SyncPipelineWrapper, - simplehashProvider *simplehash.Provider, -) *multichain.OptimismProvider { - panic(wire.Build( - wire.Struct(new(multichain.OptimismProvider), "*"), - wire.Bind(new(multichain.ContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokenMetadataBatcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokenMetadataFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensByContractWalletFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensByTokenIdentifiersFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensIncrementalContractFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(syncPipeline)), - )) -} - -func optimismSyncPipelineInjector( - ctx context.Context, - httpClient *http.Client, - chain persist.Chain, - simplehashProvider *simplehash.Provider, -) (*wrapper.SyncPipelineWrapper, func()) { - panic(wire.Build( - wire.Struct(new(wrapper.SyncPipelineWrapper), "*"), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), - customMetadataHandlersInjector, - )) -} - -func arbitrumInjector(context.Context, *http.Client) (*multichain.ArbitrumProvider, func()) { - panic(wire.Build( - wire.Value(persist.ChainArbitrum), - simplehash.NewProvider, - arbitrumProviderInjector, - arbitrumSyncPipelineInjector, - )) -} - -func arbitrumProviderInjector( - syncPipeline *wrapper.SyncPipelineWrapper, - simplehashProvider *simplehash.Provider, -) *multichain.ArbitrumProvider { - panic(wire.Build( - wire.Struct(new(multichain.ArbitrumProvider), "*"), - wire.Bind(new(multichain.ContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokenMetadataBatcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokenMetadataFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensByTokenIdentifiersFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensByContractWalletFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensIncrementalContractFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(syncPipeline)), - )) -} - -func arbitrumSyncPipelineInjector( - ctx context.Context, - httpClient *http.Client, - chain persist.Chain, - simplehashProvider *simplehash.Provider, -) (*wrapper.SyncPipelineWrapper, func()) { - panic(wire.Build( - wire.Struct(new(wrapper.SyncPipelineWrapper), "*"), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), - customMetadataHandlersInjector, - )) -} - -func poapInjector(envInit, *http.Client) *multichain.PoapProvider { - panic(wire.Build( - poapProviderInjector, - poap.NewProvider, - )) -} - -func poapProviderInjector(poapProvider *poap.Provider) *multichain.PoapProvider { - panic(wire.Build( - wire.Struct(new(multichain.PoapProvider), "*"), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(poapProvider)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(poapProvider)), - wire.Bind(new(multichain.TokenMetadataFetcher), util.ToPointer(poapProvider)), - wire.Bind(new(multichain.TokenDescriptorsFetcher), util.ToPointer(poapProvider)), - )) -} - -func zoraInjector(envInit, context.Context, *http.Client) (*multichain.ZoraProvider, func()) { - panic(wire.Build( - wire.Value(persist.ChainZora), - simplehash.NewProvider, - zoraProviderInjector, - zoraSyncPipelineInjector, - )) -} - -func zoraProviderInjector( - syncPipeline *wrapper.SyncPipelineWrapper, - simplehashProvider *simplehash.Provider, -) *multichain.ZoraProvider { - panic(wire.Build( - wire.Struct(new(multichain.ZoraProvider), "*"), - wire.Bind(new(multichain.ContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokenMetadataBatcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokenMetadataFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensByContractWalletFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensByTokenIdentifiersFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensIncrementalContractFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(syncPipeline)), - )) -} - -func zoraSyncPipelineInjector( - ctx context.Context, - httpClient *http.Client, - chain persist.Chain, - simplehashProvider *simplehash.Provider, -) (*wrapper.SyncPipelineWrapper, func()) { - panic(wire.Build( - wire.Struct(new(wrapper.SyncPipelineWrapper), "*"), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), - customMetadataHandlersInjector, - )) -} - -func baseInjector(context.Context, *http.Client) (*multichain.BaseProvider, func()) { - panic(wire.Build( - wire.Value(persist.ChainBase), - simplehash.NewProvider, - baseProvidersInjector, - baseSyncPipelineInjector, - )) -} - -func baseProvidersInjector( - syncPipeline *wrapper.SyncPipelineWrapper, - simplehashProvider *simplehash.Provider, -) *multichain.BaseProvider { - panic(wire.Build( - wire.Struct(new(multichain.BaseProvider), "*"), - wire.Bind(new(multichain.ContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokenMetadataBatcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokenMetadataFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensByContractWalletFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensByTokenIdentifiersFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensIncrementalContractFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(syncPipeline)), - )) -} - -func baseSyncPipelineInjector( - ctx context.Context, - httpClient *http.Client, - chain persist.Chain, - simplehashProvider *simplehash.Provider, -) (*wrapper.SyncPipelineWrapper, func()) { - panic(wire.Build( - wire.Struct(new(wrapper.SyncPipelineWrapper), "*"), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), - customMetadataHandlersInjector, - )) -} - -func polygonInjector(context.Context, *http.Client) (*multichain.PolygonProvider, func()) { - panic(wire.Build( - wire.Value(persist.ChainPolygon), - simplehash.NewProvider, - polygonProvidersInjector, - polygonSyncPipelineInjector, - )) -} - -func polygonProvidersInjector( - syncPipeline *wrapper.SyncPipelineWrapper, - simplehashProvider *simplehash.Provider, -) *multichain.PolygonProvider { - panic(wire.Build( - wire.Struct(new(multichain.PolygonProvider), "*"), - wire.Bind(new(multichain.ContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensIncrementalContractFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokenMetadataBatcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensByContractWalletFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokensByTokenIdentifiersFetcher), util.ToPointer(syncPipeline)), - wire.Bind(new(multichain.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenMetadataFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), - )) -} - -func polygonSyncPipelineInjector( - ctx context.Context, - httpClient *http.Client, - chain persist.Chain, - simplehashProvider *simplehash.Provider, -) (*wrapper.SyncPipelineWrapper, func()) { - panic(wire.Build( - wire.Struct(new(wrapper.SyncPipelineWrapper), "*"), - wire.Bind(new(multichain.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), - wire.Bind(new(multichain.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), - customMetadataHandlersInjector, - )) -} - -func tokenProcessingSubmitterInjector(context.Context) *tokenmanage.TokenProcessingSubmitter { - panic(wire.Build( - wire.Struct(new(tokenmanage.TokenProcessingSubmitter), "*"), - task.NewClient, - wire.Struct(new(tokenmanage.Registry), "*"), - newTokenManageCache, - )) -} diff --git a/service/multichain/alchemy/alchemy.go b/service/multichain/alchemy/alchemy.go index 03a79f869..967c87236 100644 --- a/service/multichain/alchemy/alchemy.go +++ b/service/multichain/alchemy/alchemy.go @@ -15,7 +15,7 @@ import ( "github.com/mikeydub/go-gallery/env" "github.com/mikeydub/go-gallery/service/logger" - "github.com/mikeydub/go-gallery/service/multichain" + "github.com/mikeydub/go-gallery/service/multichain/common" "github.com/mikeydub/go-gallery/service/persist" "github.com/mikeydub/go-gallery/util" ) @@ -206,7 +206,7 @@ func NewProvider(httpClient *http.Client, chain persist.Chain) *Provider { } // GetTokensByWalletAddress retrieves tokens for a wallet address on the Ethereum Blockchain -func (d *Provider) GetTokensByWalletAddress(ctx context.Context, addr persist.Address) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (d *Provider) GetTokensByWalletAddress(ctx context.Context, addr persist.Address) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { u := mustGetNftsEndpoint(d.alchemyAPIURL) setOwner(u, addr) setWithMetadata(u) @@ -221,8 +221,8 @@ func (d *Provider) GetTokensByWalletAddress(ctx context.Context, addr persist.Ad } // GetTokensIncrementallyByWalletAddress retrieves tokens for a wallet address on the Ethereum Blockchain -func (d *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, addr persist.Address) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { - rec := make(chan multichain.ChainAgnosticTokensAndContracts) +func (d *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, addr persist.Address) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + rec := make(chan common.ChainAgnosticTokensAndContracts) errChan := make(chan error) u := mustGetNftsEndpoint(d.alchemyAPIURL) setOwner(u, addr) @@ -258,7 +258,7 @@ func (d *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ad break outer } cTokens, cContracts := alchemyTokensToChainAgnosticTokensForOwner(persist.EthereumAddress(addr), tokens) - rec <- multichain.ChainAgnosticTokensAndContracts{ + rec <- common.ChainAgnosticTokensAndContracts{ Tokens: cTokens, Contracts: cContracts, } @@ -270,8 +270,8 @@ func (d *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ad } // GetTokensIncrementallyByContractAddress retrieves tokens incrementaly for a contract address on the Ethereum Blockchain -func (d *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, addr persist.Address, limit int) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { - rec := make(chan multichain.ChainAgnosticTokensAndContracts) +func (d *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, addr persist.Address, limit int) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + rec := make(chan common.ChainAgnosticTokensAndContracts) errChan := make(chan error) u := mustGetNftsForCollectionEndpoint(d.alchemyAPIURL) @@ -312,10 +312,10 @@ func (d *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, return } if len(cContracts) == 0 { - errChan <- multichain.ErrProviderContractNotFound{Contract: addr, Chain: d.chain} + errChan <- fmt.Errorf("%s not found", persist.ContractIdentifiers{ContractAddress: addr, Chain: d.chain}) return } - rec <- multichain.ChainAgnosticTokensAndContracts{ + rec <- common.ChainAgnosticTokensAndContracts{ Tokens: cTokens, Contracts: cContracts, } @@ -440,7 +440,7 @@ func (d *Provider) getOwnersForContract(ctx context.Context, contract persist.Et return result.Owners, nil } -func (d *Provider) getTokenWithMetadata(ctx context.Context, ti multichain.ChainAgnosticIdentifiers, forceRefresh bool, timeout time.Duration) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (d *Provider) getTokenWithMetadata(ctx context.Context, ti common.ChainAgnosticIdentifiers, forceRefresh bool, timeout time.Duration) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { if timeout == 0 { timeout = (time.Second * 20) / time.Millisecond } @@ -453,40 +453,40 @@ func (d *Provider) getTokenWithMetadata(ctx context.Context, ti multichain.Chain req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } resp, err := d.httpClient.Do(req) if err != nil { - return nil, multichain.ChainAgnosticContract{}, fmt.Errorf("failed to get token metadata from alchemy api: %w (url: %s)", err, u.String()) + return nil, common.ChainAgnosticContract{}, fmt.Errorf("failed to get token metadata from alchemy api: %w (url: %s)", err, u.String()) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { err := util.GetErrFromResp(resp) - return nil, multichain.ChainAgnosticContract{}, fmt.Errorf("failed to get token metadata from alchemy api: %s (%w)", resp.Status, err) + return nil, common.ChainAgnosticContract{}, fmt.Errorf("failed to get token metadata from alchemy api: %s (%w)", resp.Status, err) } // will have most of the fields empty var token Token if err := json.NewDecoder(resp.Body).Decode(&token); err != nil { - return nil, multichain.ChainAgnosticContract{}, fmt.Errorf("failed to decode token metadata response: %w (url: %s)", err, u.String()) + return nil, common.ChainAgnosticContract{}, fmt.Errorf("failed to decode token metadata response: %w (url: %s)", err, u.String()) } tokens, contracts, err := d.alchemyTokensToChainAgnosticTokens(ctx, []Token{token}) if err != nil { - return nil, multichain.ChainAgnosticContract{}, fmt.Errorf("failed to convert token to chain agnostic token: %w (url: %s)", err, u.String()) + return nil, common.ChainAgnosticContract{}, fmt.Errorf("failed to convert token to chain agnostic token: %w (url: %s)", err, u.String()) } if len(contracts) == 0 { - return nil, multichain.ChainAgnosticContract{}, fmt.Errorf("failed to get contracts from alchemy api") + return nil, common.ChainAgnosticContract{}, fmt.Errorf("failed to get contracts from alchemy api") } return tokens, contracts[0], nil } -func (d *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { +func (d *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { tokens, _, err := d.getTokenWithMetadata(ctx, ti, true, 0) if err != nil { return nil, err @@ -498,7 +498,7 @@ func (d *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti mu } // GetTokensByContractAddress retrieves tokens for a contract address on the Ethereum Blockchain -func (d *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, limit, offset int) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (d *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, limit, offset int) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { u := mustGetNftsForCollectionEndpoint(d.alchemyAPIURL) setContractAddress(u, contractAddress) setWithMetadata(u) @@ -507,22 +507,22 @@ func (d *Provider) GetTokensByContractAddress(ctx context.Context, contractAddre tokens, err := getNFTsPaginate(ctx, u.String(), 100, "startToken", limit, offset, "", d.httpClient, nil, &getNFTsForCollectionResponse{}) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } cTokens, cContracts, err := d.alchemyContractTokensToChainAgnosticTokens(ctx, contractAddress, tokens) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } if len(cContracts) == 0 { - return nil, multichain.ChainAgnosticContract{}, multichain.ErrProviderContractNotFound{Contract: contractAddress, Chain: d.chain} + return nil, common.ChainAgnosticContract{}, fmt.Errorf("%s not found", persist.ContractIdentifiers{ContractAddress: contractAddress, Chain: d.chain}) } return cTokens, cContracts[0], nil } -func (d *Provider) alchemyContractTokensToChainAgnosticTokens(ctx context.Context, contractAddress persist.Address, tokens []Token) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (d *Provider) alchemyContractTokensToChainAgnosticTokens(ctx context.Context, contractAddress persist.Address, tokens []Token) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { owners, err := d.getOwnersForContract(ctx, persist.EthereumAddress(contractAddress)) if err != nil { return nil, nil, err @@ -549,37 +549,37 @@ func (d *Provider) alchemyContractTokensToChainAgnosticTokens(ctx context.Contex return cTokens, cContracts, nil } -func (d *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, tokenIdentifiers multichain.ChainAgnosticIdentifiers, ownerAddress persist.Address) (multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (d *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, tokenIdentifiers common.ChainAgnosticIdentifiers, ownerAddress persist.Address) (common.ChainAgnosticToken, common.ChainAgnosticContract, error) { tokens, contract, err := d.getTokenWithMetadata(ctx, tokenIdentifiers, true, 0) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } if len(tokens) == 0 { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, fmt.Errorf("no token found for contract address %s and token ID %s", tokenIdentifiers.ContractAddress, tokenIdentifiers.TokenID) + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, fmt.Errorf("no token found for contract address %s and token ID %s", tokenIdentifiers.ContractAddress, tokenIdentifiers.TokenID) } - token, ok := util.FindFirst(tokens, func(t multichain.ChainAgnosticToken) bool { + token, ok := util.FindFirst(tokens, func(t common.ChainAgnosticToken) bool { return t.OwnerAddress == ownerAddress }) if !ok { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, fmt.Errorf("no token found for contract address %s and token ID %s and owner address %s", tokenIdentifiers.ContractAddress, tokenIdentifiers.TokenID, ownerAddress) + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, fmt.Errorf("no token found for contract address %s and token ID %s and owner address %s", tokenIdentifiers.ContractAddress, tokenIdentifiers.TokenID, ownerAddress) } return token, contract, nil } -func (d *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentifiers multichain.ChainAgnosticIdentifiers) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (d *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentifiers common.ChainAgnosticIdentifiers) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { return d.getTokenWithMetadata(ctx, tokenIdentifiers, true, 0) } -func (d *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (multichain.ChainAgnosticTokenDescriptors, multichain.ChainAgnosticContractDescriptors, error) { +func (d *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) (common.ChainAgnosticTokenDescriptors, common.ChainAgnosticContractDescriptors, error) { tokens, contract, err := d.getTokenWithMetadata(ctx, ti, true, 0) if err != nil { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, err + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, err } if len(tokens) == 0 { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, fmt.Errorf("no token found for contract address %s and token ID %s", ti.ContractAddress, ti.TokenID) + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, fmt.Errorf("no token found for contract address %s and token ID %s", ti.ContractAddress, ti.TokenID) } firstToken := tokens[0] return firstToken.Descriptors, contract.Descriptors, nil @@ -591,34 +591,34 @@ type GetContractMetadataResponse struct { } // GetContractByAddress retrieves an ethereum contract by address -func (d *Provider) GetContractByAddress(ctx context.Context, addr persist.Address) (multichain.ChainAgnosticContract, error) { +func (d *Provider) GetContractByAddress(ctx context.Context, addr persist.Address) (common.ChainAgnosticContract, error) { u := mustGetContractMetadataEndpoint(d.alchemyAPIURL) setContractAddress(u, addr) req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) if err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } resp, err := d.httpClient.Do(req) if err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return multichain.ChainAgnosticContract{}, fmt.Errorf("failed to get contract metadata from alchemy api: %s", resp.Status) + return common.ChainAgnosticContract{}, fmt.Errorf("failed to get contract metadata from alchemy api: %s", resp.Status) } var contractMetadataResponse GetContractMetadataResponse if err := json.NewDecoder(resp.Body).Decode(&contractMetadataResponse); err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } - return multichain.ChainAgnosticContract{ + return common.ChainAgnosticContract{ Address: persist.Address(contractMetadataResponse.Address), - Descriptors: multichain.ChainAgnosticContractDescriptors{ + Descriptors: common.ChainAgnosticContractDescriptors{ Symbol: contractMetadataResponse.ContractMetadata.Symbol, Name: contractMetadataResponse.ContractMetadata.Name, OwnerAddress: persist.Address(contractMetadataResponse.ContractMetadata.ContractDeployer), @@ -629,7 +629,7 @@ func (d *Provider) GetContractByAddress(ctx context.Context, addr persist.Addres } -func (d *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, tIDs []multichain.ChainAgnosticIdentifiers) ([]persist.TokenMetadata, error) { +func (d *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, tIDs []common.ChainAgnosticIdentifiers) ([]persist.TokenMetadata, error) { type tokenRequest struct { ContractAddress string `json:"contractAddress"` TokenID string `json:"tokenId"` @@ -657,7 +657,7 @@ func (d *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, u := mustGetNftMetadataBatchEndpoint(d.alchemyAPIURL) // alchemy doesn't return tokens in the same order as the input - lookup := make(map[multichain.ChainAgnosticIdentifiers]persist.TokenMetadata) + lookup := make(map[common.ChainAgnosticIdentifiers]persist.TokenMetadata) for i, c := range chunks { batchID := i + 1 @@ -704,7 +704,7 @@ func (d *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, } for _, m := range batchResp { - tID := multichain.ChainAgnosticIdentifiers{ContractAddress: persist.Address(m.Contract.Address), TokenID: persist.MustTokenID(m.Id.TokenId)} + tID := common.ChainAgnosticIdentifiers{ContractAddress: persist.Address(m.Contract.Address), TokenID: persist.MustTokenID(m.Id.TokenId)} lookup[tID] = alchemyMetadataToMetadata(m.Metadata) } } @@ -717,9 +717,9 @@ func (d *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, return metadatas, nil } -func alchemyTokensToChainAgnosticTokensForOwner(owner persist.EthereumAddress, tokens []Token) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract) { - chainAgnosticTokens := make([]multichain.ChainAgnosticToken, 0, len(tokens)) - chainAgnosticContracts := make([]multichain.ChainAgnosticContract, 0, len(tokens)) +func alchemyTokensToChainAgnosticTokensForOwner(owner persist.EthereumAddress, tokens []Token) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract) { + chainAgnosticTokens := make([]common.ChainAgnosticToken, 0, len(tokens)) + chainAgnosticContracts := make([]common.ChainAgnosticContract, 0, len(tokens)) seenContracts := make(map[persist.Address]bool) for _, token := range tokens { cToken, cContract := alchemyTokenToChainAgnosticToken(owner, token) @@ -732,9 +732,9 @@ func alchemyTokensToChainAgnosticTokensForOwner(owner persist.EthereumAddress, t return chainAgnosticTokens, chainAgnosticContracts } -func (d *Provider) alchemyTokensToChainAgnosticTokens(ctx context.Context, tokens []Token) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { - chainAgnosticTokens := make([]multichain.ChainAgnosticToken, 0, len(tokens)) - chainAgnosticContracts := make([]multichain.ChainAgnosticContract, 0, len(tokens)) +func (d *Provider) alchemyTokensToChainAgnosticTokens(ctx context.Context, tokens []Token) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { + chainAgnosticTokens := make([]common.ChainAgnosticToken, 0, len(tokens)) + chainAgnosticContracts := make([]common.ChainAgnosticContract, 0, len(tokens)) seenContracts := make(map[persist.Address]bool) for _, token := range tokens { owners, err := d.getOwnersForToken(ctx, token) @@ -753,9 +753,9 @@ func (d *Provider) alchemyTokensToChainAgnosticTokens(ctx context.Context, token return chainAgnosticTokens, chainAgnosticContracts, nil } -func alchemyTokensToChainAgnosticTokensWithOwners(ctx context.Context, tokens map[persist.EthereumAddress][]Token) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract) { - chainAgnosticTokens := make([]multichain.ChainAgnosticToken, 0, len(tokens)) - chainAgnosticContracts := make([]multichain.ChainAgnosticContract, 0, len(tokens)) +func alchemyTokensToChainAgnosticTokensWithOwners(ctx context.Context, tokens map[persist.EthereumAddress][]Token) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract) { + chainAgnosticTokens := make([]common.ChainAgnosticToken, 0, len(tokens)) + chainAgnosticContracts := make([]common.ChainAgnosticContract, 0, len(tokens)) seenContracts := make(map[persist.Address]bool) for owner, ownerTokens := range tokens { for _, token := range ownerTokens { @@ -808,7 +808,7 @@ func alchemyMetadataToMetadata(m any) persist.TokenMetadata { return metadata } -func alchemyTokenToChainAgnosticToken(owner persist.EthereumAddress, token Token) (multichain.ChainAgnosticToken, multichain.ChainAgnosticContract) { +func alchemyTokenToChainAgnosticToken(owner persist.EthereumAddress, token Token) (common.ChainAgnosticToken, common.ChainAgnosticContract) { var tokenType persist.TokenType switch token.ID.TokenMetadata.TokenType { @@ -838,9 +838,9 @@ func alchemyTokenToChainAgnosticToken(owner persist.EthereumAddress, token Token description = descriptionAsArr[0] } - t := multichain.ChainAgnosticToken{ + t := common.ChainAgnosticToken{ TokenType: tokenType, - Descriptors: multichain.ChainAgnosticTokenDescriptors{ + Descriptors: common.ChainAgnosticTokenDescriptors{ Name: token.Title, Description: description, }, @@ -860,9 +860,9 @@ func alchemyTokenToChainAgnosticToken(owner persist.EthereumAddress, token Token contractSpam := contractNameIsSpam(token.ContractMetadata.Name) - return t, multichain.ChainAgnosticContract{ + return t, common.ChainAgnosticContract{ Address: persist.Address(token.Contract.Address), - Descriptors: multichain.ChainAgnosticContractDescriptors{ + Descriptors: common.ChainAgnosticContractDescriptors{ Symbol: token.ContractMetadata.Symbol, Name: token.ContractMetadata.Name, OwnerAddress: persist.Address(token.ContractMetadata.ContractDeployer), diff --git a/service/multichain/common/common.go b/service/multichain/common/common.go new file mode 100644 index 000000000..e22ead07a --- /dev/null +++ b/service/multichain/common/common.go @@ -0,0 +1,112 @@ +package common + +import ( + "context" + "fmt" + + "github.com/mikeydub/go-gallery/service/persist" +) + +// ChainAgnosticIdentifiers identify tokens despite their chain +type ChainAgnosticIdentifiers struct { + ContractAddress persist.Address `json:"contract_address"` + TokenID persist.HexTokenID `json:"token_id"` +} + +func (t ChainAgnosticIdentifiers) String() string { + return fmt.Sprintf("token(address=%s, tokenID=%s)", t.ContractAddress, t.TokenID.ToDecimalTokenID()) +} + +// Verifier can verify that a signature is signed by a given key +type Verifier interface { + VerifySignature(ctx context.Context, pubKey persist.PubKey, walletType persist.WalletType, nonce string, sig string) (bool, error) +} + +type TokenIdentifierOwnerFetcher interface { + GetTokenByTokenIdentifiersAndOwner(context.Context, ChainAgnosticIdentifiers, persist.Address) (ChainAgnosticToken, ChainAgnosticContract, error) +} + +type TokensByContractWalletFetcher interface { + GetTokensByContractWallet(ctx context.Context, contract persist.ChainAddress, wallet persist.Address) ([]ChainAgnosticToken, ChainAgnosticContract, error) +} + +type TokensByTokenIdentifiersFetcher interface { + GetTokensByTokenIdentifiers(context.Context, ChainAgnosticIdentifiers) ([]ChainAgnosticToken, ChainAgnosticContract, error) +} + +// TokensIncrementalOwnerFetcher supports fetching tokens for syncing incrementally +type TokensIncrementalOwnerFetcher interface { + // NOTE: implementation MUST close the rec channel + GetTokensIncrementallyByWalletAddress(ctx context.Context, address persist.Address) (<-chan ChainAgnosticTokensAndContracts, <-chan error) +} + +// TokensIncrementalContractFetcher supports fetching tokens by contract for syncing incrementally +type TokensIncrementalContractFetcher interface { + // NOTE: implementations MUST close the rec channel + // maxLimit is not for pagination, it is to make sure we don't fetch a bajilion tokens from an omnibus contract + GetTokensIncrementallyByContractAddress(ctx context.Context, address persist.Address, maxLimit int) (<-chan ChainAgnosticTokensAndContracts, <-chan error) +} + +type ContractFetcher interface { + GetContractByAddress(ctx context.Context, contract persist.Address) (ChainAgnosticContract, error) +} + +type ContractsCreatorFetcher interface { + GetContractsByCreatorAddress(ctx context.Context, owner persist.Address) ([]ChainAgnosticContract, error) +} + +// TokenMetadataFetcher supports fetching token metadata +type TokenMetadataFetcher interface { + GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti ChainAgnosticIdentifiers) (persist.TokenMetadata, error) +} + +type TokenMetadataBatcher interface { + GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, tIDs []ChainAgnosticIdentifiers) ([]persist.TokenMetadata, error) +} + +type TokenDescriptorsFetcher interface { + GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, ti ChainAgnosticIdentifiers) (ChainAgnosticTokenDescriptors, ChainAgnosticContractDescriptors, error) +} + +// ChainAgnosticToken is a token that is agnostic to the chain it is on +type ChainAgnosticToken struct { + Descriptors ChainAgnosticTokenDescriptors `json:"descriptors"` + TokenType persist.TokenType `json:"token_type"` + TokenURI persist.TokenURI `json:"token_uri"` + TokenID persist.HexTokenID `json:"token_id"` + Quantity persist.HexString `json:"quantity"` + OwnerAddress persist.Address `json:"owner_address"` + TokenMetadata persist.TokenMetadata `json:"metadata"` + ContractAddress persist.Address `json:"contract_address"` + FallbackMedia persist.FallbackMedia `json:"fallback_media"` + ExternalURL string `json:"external_url"` + BlockNumber persist.BlockNumber `json:"block_number"` + IsSpam *bool `json:"is_spam"` +} + +// ChainAgnosticContract is a contract that is agnostic to the chain it is on +type ChainAgnosticContract struct { + Descriptors ChainAgnosticContractDescriptors `json:"descriptors"` + Address persist.Address `json:"address"` + IsSpam *bool `json:"is_spam"` + LatestBlock persist.BlockNumber `json:"latest_block"` +} + +type ChainAgnosticTokensAndContracts struct { + Tokens []ChainAgnosticToken `json:"tokens"` + Contracts []ChainAgnosticContract `json:"contracts"` +} + +// ChainAgnosticTokenDescriptors are the fields that describe a token but cannot be used to uniquely identify it +type ChainAgnosticTokenDescriptors struct { + Name string `json:"name"` + Description string `json:"description"` +} + +type ChainAgnosticContractDescriptors struct { + Symbol string `json:"symbol"` + Name string `json:"name"` + Description string `json:"description"` + ProfileImageURL string `json:"profile_image_url"` + OwnerAddress persist.Address `json:"owner_address"` +} diff --git a/service/multichain/config.go b/service/multichain/config.go index 4a0f3d198..2f91a5f5e 100644 --- a/service/multichain/config.go +++ b/service/multichain/config.go @@ -1,6 +1,7 @@ package multichain import ( + "github.com/mikeydub/go-gallery/service/multichain/common" "github.com/mikeydub/go-gallery/service/persist" ) @@ -18,101 +19,101 @@ type ChainProvider struct { } type EthereumProvider struct { - ContractFetcher - ContractsCreatorFetcher - TokenDescriptorsFetcher - TokenIdentifierOwnerFetcher - TokenMetadataBatcher - TokenMetadataFetcher - TokensByContractWalletFetcher - TokensByTokenIdentifiersFetcher - TokensIncrementalContractFetcher - TokensIncrementalOwnerFetcher - Verifier + common.ContractFetcher + common.ContractsCreatorFetcher + common.TokenDescriptorsFetcher + common.TokenIdentifierOwnerFetcher + common.TokenMetadataBatcher + common.TokenMetadataFetcher + common.TokensByContractWalletFetcher + common.TokensByTokenIdentifiersFetcher + common.TokensIncrementalContractFetcher + common.TokensIncrementalOwnerFetcher + common.Verifier } type TezosProvider struct { - ContractFetcher - ContractsCreatorFetcher - TokenDescriptorsFetcher - TokenIdentifierOwnerFetcher - TokenMetadataBatcher - TokenMetadataFetcher - TokensByContractWalletFetcher - TokensByTokenIdentifiersFetcher - TokensIncrementalContractFetcher - TokensIncrementalOwnerFetcher - Verifier + common.ContractFetcher + common.ContractsCreatorFetcher + common.TokenDescriptorsFetcher + common.TokenIdentifierOwnerFetcher + common.TokenMetadataBatcher + common.TokenMetadataFetcher + common.TokensByContractWalletFetcher + common.TokensByTokenIdentifiersFetcher + common.TokensIncrementalContractFetcher + common.TokensIncrementalOwnerFetcher + common.Verifier } type OptimismProvider struct { - ContractFetcher - ContractsCreatorFetcher - TokenDescriptorsFetcher - TokenIdentifierOwnerFetcher - TokenMetadataBatcher - TokenMetadataFetcher - TokensByContractWalletFetcher - TokensByTokenIdentifiersFetcher - TokensIncrementalContractFetcher - TokensIncrementalOwnerFetcher + common.ContractFetcher + common.ContractsCreatorFetcher + common.TokenDescriptorsFetcher + common.TokenIdentifierOwnerFetcher + common.TokenMetadataBatcher + common.TokenMetadataFetcher + common.TokensByContractWalletFetcher + common.TokensByTokenIdentifiersFetcher + common.TokensIncrementalContractFetcher + common.TokensIncrementalOwnerFetcher } type ArbitrumProvider struct { - ContractFetcher - ContractsCreatorFetcher - TokenDescriptorsFetcher - TokenIdentifierOwnerFetcher - TokenMetadataBatcher - TokenMetadataFetcher - TokensByContractWalletFetcher - TokensByTokenIdentifiersFetcher - TokensIncrementalContractFetcher - TokensIncrementalOwnerFetcher + common.ContractFetcher + common.ContractsCreatorFetcher + common.TokenDescriptorsFetcher + common.TokenIdentifierOwnerFetcher + common.TokenMetadataBatcher + common.TokenMetadataFetcher + common.TokensByContractWalletFetcher + common.TokensByTokenIdentifiersFetcher + common.TokensIncrementalContractFetcher + common.TokensIncrementalOwnerFetcher } type PoapProvider struct { - TokenDescriptorsFetcher - TokenMetadataFetcher - TokensIncrementalOwnerFetcher - TokenIdentifierOwnerFetcher + common.TokenDescriptorsFetcher + common.TokenMetadataFetcher + common.TokensIncrementalOwnerFetcher + common.TokenIdentifierOwnerFetcher } type ZoraProvider struct { - ContractFetcher - ContractsCreatorFetcher - TokenDescriptorsFetcher - TokenIdentifierOwnerFetcher - TokenMetadataBatcher - TokenMetadataFetcher - TokensByContractWalletFetcher - TokensByTokenIdentifiersFetcher - TokensIncrementalContractFetcher - TokensIncrementalOwnerFetcher + common.ContractFetcher + common.ContractsCreatorFetcher + common.TokenDescriptorsFetcher + common.TokenIdentifierOwnerFetcher + common.TokenMetadataBatcher + common.TokenMetadataFetcher + common.TokensByContractWalletFetcher + common.TokensByTokenIdentifiersFetcher + common.TokensIncrementalContractFetcher + common.TokensIncrementalOwnerFetcher } type BaseProvider struct { - ContractFetcher - ContractsCreatorFetcher - TokenDescriptorsFetcher - TokenIdentifierOwnerFetcher - TokenMetadataBatcher - TokenMetadataFetcher - TokensByContractWalletFetcher - TokensByTokenIdentifiersFetcher - TokensIncrementalContractFetcher - TokensIncrementalOwnerFetcher + common.ContractFetcher + common.ContractsCreatorFetcher + common.TokenDescriptorsFetcher + common.TokenIdentifierOwnerFetcher + common.TokenMetadataBatcher + common.TokenMetadataFetcher + common.TokensByContractWalletFetcher + common.TokensByTokenIdentifiersFetcher + common.TokensIncrementalContractFetcher + common.TokensIncrementalOwnerFetcher } type PolygonProvider struct { - ContractFetcher - ContractsCreatorFetcher - TokenDescriptorsFetcher - TokenIdentifierOwnerFetcher - TokenMetadataBatcher - TokenMetadataFetcher - TokensByContractWalletFetcher - TokensByTokenIdentifiersFetcher - TokensIncrementalContractFetcher - TokensIncrementalOwnerFetcher + common.ContractFetcher + common.ContractsCreatorFetcher + common.TokenDescriptorsFetcher + common.TokenIdentifierOwnerFetcher + common.TokenMetadataBatcher + common.TokenMetadataFetcher + common.TokensByContractWalletFetcher + common.TokensByTokenIdentifiersFetcher + common.TokensIncrementalContractFetcher + common.TokensIncrementalOwnerFetcher } diff --git a/service/multichain/custom_metadata.go b/service/multichain/custom/custom_metadata.go similarity index 95% rename from service/multichain/custom_metadata.go rename to service/multichain/custom/custom_metadata.go index 2bd95a2ce..c3565ea08 100644 --- a/service/multichain/custom_metadata.go +++ b/service/multichain/custom/custom_metadata.go @@ -1,4 +1,4 @@ -package multichain +package custom import ( "bytes" @@ -15,7 +15,7 @@ import ( svg "github.com/ajstarks/svgo" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" + ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/everFinance/goar" shell "github.com/ipfs/go-ipfs-api" @@ -25,6 +25,7 @@ import ( "github.com/mikeydub/go-gallery/service/eth" "github.com/mikeydub/go-gallery/service/logger" "github.com/mikeydub/go-gallery/service/media" + "github.com/mikeydub/go-gallery/service/multichain/common" "github.com/mikeydub/go-gallery/service/persist" "github.com/mikeydub/go-gallery/service/rpc" "github.com/mikeydub/go-gallery/util" @@ -81,15 +82,15 @@ func (c *CustomMetadataHandlers) HandlerFor(t persist.TokenIdentifiers) metadata } } -func (c *CustomMetadataHandlers) AddToToken(ctx context.Context, chain persist.Chain, t ChainAgnosticToken) ChainAgnosticToken { - tID := ChainAgnosticIdentifiers{ContractAddress: t.ContractAddress, TokenID: t.TokenID} +func (c *CustomMetadataHandlers) AddToToken(ctx context.Context, chain persist.Chain, t common.ChainAgnosticToken) common.ChainAgnosticToken { + tID := common.ChainAgnosticIdentifiers{ContractAddress: t.ContractAddress, TokenID: t.TokenID} m := c.Load(ctx, chain, tID, t.TokenMetadata) t.TokenMetadata = m return t } -func (c *CustomMetadataHandlers) AddToPage(ctx context.Context, chain persist.Chain, recCh <-chan ChainAgnosticTokensAndContracts, errIn <-chan error) (<-chan ChainAgnosticTokensAndContracts, <-chan error) { - outCh := make(chan ChainAgnosticTokensAndContracts, 2*10) +func (c *CustomMetadataHandlers) AddToPage(ctx context.Context, chain persist.Chain, recCh <-chan common.ChainAgnosticTokensAndContracts, errIn <-chan error) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + outCh := make(chan common.ChainAgnosticTokensAndContracts, 2*10) errOut := make(chan error) go func() { defer close(outCh) @@ -116,7 +117,7 @@ func (c *CustomMetadataHandlers) AddToPage(ctx context.Context, chain persist.Ch return outCh, errOut } -func (c *CustomMetadataHandlers) Load(ctx context.Context, chain persist.Chain, t ChainAgnosticIdentifiers, oldMetadata ...persist.TokenMetadata) persist.TokenMetadata { +func (c *CustomMetadataHandlers) Load(ctx context.Context, chain persist.Chain, t common.ChainAgnosticIdentifiers, oldMetadata ...persist.TokenMetadata) persist.TokenMetadata { tID := persist.NewTokenIdentifiers(t.ContractAddress, t.TokenID, chain) h := c.HandlerFor(tID) if h == nil { @@ -130,12 +131,12 @@ func (c *CustomMetadataHandlers) Load(ctx context.Context, chain persist.Chain, return m } -func (c *CustomMetadataHandlers) LoadMetadataAll(ctx context.Context, chain persist.Chain, tokens []ChainAgnosticToken) []persist.TokenMetadata { +func (c *CustomMetadataHandlers) LoadMetadataAll(ctx context.Context, chain persist.Chain, tokens []common.ChainAgnosticToken) []persist.TokenMetadata { tokens = c.LoadAll(ctx, chain, tokens) - return util.MapWithoutError(tokens, func(t ChainAgnosticToken) persist.TokenMetadata { return t.TokenMetadata }) + return util.MapWithoutError(tokens, func(t common.ChainAgnosticToken) persist.TokenMetadata { return t.TokenMetadata }) } -func (c *CustomMetadataHandlers) LoadAll(ctx context.Context, chain persist.Chain, tokens []ChainAgnosticToken) []ChainAgnosticToken { +func (c *CustomMetadataHandlers) LoadAll(ctx context.Context, chain persist.Chain, tokens []common.ChainAgnosticToken) []common.ChainAgnosticToken { for i, t := range tokens { tokens[i] = c.AddToToken(ctx, chain, t) } @@ -517,7 +518,7 @@ func newEnsHandler() metadataHandler { func newCryptopunkHandler(ethClient *ethclient.Client) metadataHandler { return func(ctx context.Context, t persist.TokenIdentifiers, _ ...persist.TokenMetadata) (persist.TokenMetadata, error) { - dataContract, err := contracts.NewCryptopunksDataCaller(common.HexToAddress("0x16f5a35647d6f03d5d3da7b35409d65ba03af3b2"), ethClient) + dataContract, err := contracts.NewCryptopunksDataCaller(ethcommon.HexToAddress("0x16f5a35647d6f03d5d3da7b35409d65ba03af3b2"), ethClient) if err != nil { return persist.TokenMetadata{}, err } @@ -542,7 +543,7 @@ func newCryptopunkHandler(ethClient *ethclient.Client) metadataHandler { func newZoraHandler(ethClient *ethclient.Client, ipfsClient *shell.Shell, arweaveClient *goar.Client) metadataHandler { return func(ctx context.Context, t persist.TokenIdentifiers, _ ...persist.TokenMetadata) (persist.TokenMetadata, error) { - metadataContract, err := contracts.NewZoraCaller(common.HexToAddress(t.ContractAddress.String()), ethClient) + metadataContract, err := contracts.NewZoraCaller(ethcommon.HexToAddress(t.ContractAddress.String()), ethClient) if err != nil { return persist.TokenMetadata{}, err } diff --git a/service/multichain/infura/infura.go b/service/multichain/infura/infura.go index 2b85e83b7..901064839 100644 --- a/service/multichain/infura/infura.go +++ b/service/multichain/infura/infura.go @@ -12,7 +12,7 @@ import ( "github.com/mikeydub/go-gallery/env" "github.com/mikeydub/go-gallery/service/logger" - "github.com/mikeydub/go-gallery/service/multichain" + "github.com/mikeydub/go-gallery/service/multichain/common" "github.com/mikeydub/go-gallery/service/persist" ) @@ -125,7 +125,7 @@ func NewProvider(httpClient *http.Client) *Provider { } } -func (p *Provider) GetTokensByWalletAddress(ctx context.Context, address persist.Address) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByWalletAddress(ctx context.Context, address persist.Address) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { tokens, err := getNFTsPaginate(ctx, fmt.Sprintf("%s/accounts/%s/assets/nfts", baseURL, address), "", p.httpClient, p.apiKey, p.apiSecret, &getNFTsForOwnerResponse{}) if err != nil { return nil, nil, err @@ -138,75 +138,75 @@ func (p *Provider) GetTokensByWalletAddress(ctx context.Context, address persist return p.ownedTokensToChainAgnosticTokens(ctx, address, tokens) } -func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, tids multichain.ChainAgnosticIdentifiers, owner persist.Address) (multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, tids common.ChainAgnosticIdentifiers, owner persist.Address) (common.ChainAgnosticToken, common.ChainAgnosticContract, error) { owners, err := p.getOwnersPaginate(ctx, tids, "") if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } if len(owners) == 0 { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, fmt.Errorf("no owners found for token %s with owner %s", tids, owner) + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, fmt.Errorf("no owners found for token %s with owner %s", tids, owner) } tokens, contracts, err := p.ownersToTokensForOwner(ctx, owner, owners) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } if len(tokens) == 0 { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, fmt.Errorf("no tokens found for owner %s with tids %s", owner, tids) + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, fmt.Errorf("no tokens found for owner %s with tids %s", owner, tids) } return tokens[0], contracts[0], nil } -func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tids multichain.ChainAgnosticIdentifiers) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tids common.ChainAgnosticIdentifiers) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { owners, err := p.getOwnersPaginate(ctx, tids, "") if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } if len(owners) == 0 { - return nil, multichain.ChainAgnosticContract{}, fmt.Errorf("no owners found for token %s", tids) + return nil, common.ChainAgnosticContract{}, fmt.Errorf("no owners found for token %s", tids) } tokens, contracts, err := p.ownersToTokens(ctx, owners) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } if len(tokens) == 0 || len(contracts) == 0 { - return nil, multichain.ChainAgnosticContract{}, fmt.Errorf("no tokens or contracts found for token with tids %s", tids) + return nil, common.ChainAgnosticContract{}, fmt.Errorf("no tokens or contracts found for token with tids %s", tids) } return tokens, contracts[0], nil } -func (p *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, tids multichain.ChainAgnosticIdentifiers) (multichain.ChainAgnosticTokenDescriptors, multichain.ChainAgnosticContractDescriptors, error) { +func (p *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, tids common.ChainAgnosticIdentifiers) (common.ChainAgnosticTokenDescriptors, common.ChainAgnosticContractDescriptors, error) { owners, err := p.getOwnersPaginate(ctx, tids, "") if err != nil { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, err + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, err } if len(owners) == 0 { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, fmt.Errorf("no owners found for token %s", tids) + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, fmt.Errorf("no owners found for token %s", tids) } tokens, contracts, err := p.ownersToTokensForOwner(ctx, persist.Address(owners[0].OwnerOf), []Owner{owners[0]}) if err != nil { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, err + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, err } if len(tokens) == 0 || len(contracts) == 0 { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, fmt.Errorf("no tokens or contracts found for token with tids %s", tids) + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, fmt.Errorf("no tokens or contracts found for token with tids %s", tids) } return tokens[0].Descriptors, contracts[0].Descriptors, nil } -func (d *Provider) getOwnersPaginate(ctx context.Context, tids multichain.ChainAgnosticIdentifiers, pageKey string) ([]Owner, error) { +func (d *Provider) getOwnersPaginate(ctx context.Context, tids common.ChainAgnosticIdentifiers, pageKey string) ([]Owner, error) { owners := []Owner{} @@ -320,7 +320,7 @@ type TokenMetadata struct { } // GetTokenMetadataByTokenIdentifiers retrieves a token's metadata for a given contract address and token ID -func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { +func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { meta, err := p.getMetadata(ctx, ti, true) if err != nil { logger.For(ctx).Errorf("failed to get metadata for token %s: %s", ti.TokenID, err.Error()) @@ -330,7 +330,7 @@ func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti mu } -func (p *Provider) getMetadata(ctx context.Context, ti multichain.ChainAgnosticIdentifiers, refresh bool) (persist.TokenMetadata, error) { +func (p *Provider) getMetadata(ctx context.Context, ti common.ChainAgnosticIdentifiers, refresh bool) (persist.TokenMetadata, error) { if refresh { var cancel context.CancelFunc ctx, cancel = context.WithTimeout(ctx, 10*time.Second) @@ -369,35 +369,35 @@ type ContractMetadata struct { Symbol string `json:"symbol"` } -func (p *Provider) getContractMetadata(ctx context.Context, contract persist.EthereumAddress) (multichain.ChainAgnosticContract, error) { +func (p *Provider) getContractMetadata(ctx context.Context, contract persist.EthereumAddress) (common.ChainAgnosticContract, error) { url := fmt.Sprintf("%s/nfts/%s", baseURL, contract) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } req.SetBasicAuth(p.apiKey, p.apiSecret) resp, err := p.httpClient.Do(req) if err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return multichain.ChainAgnosticContract{}, fmt.Errorf("failed to get tokens from infura api: %s", resp.Status) + return common.ChainAgnosticContract{}, fmt.Errorf("failed to get tokens from infura api: %s", resp.Status) } var contractMetadata ContractMetadata if err := json.NewDecoder(resp.Body).Decode(&contractMetadata); err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } - chainAgnosticContract := multichain.ChainAgnosticContract{ + chainAgnosticContract := common.ChainAgnosticContract{ Address: persist.Address(contract), - Descriptors: multichain.ChainAgnosticContractDescriptors{ + Descriptors: common.ChainAgnosticContractDescriptors{ Symbol: contractMetadata.Symbol, Name: contractMetadata.Name, }, @@ -406,7 +406,7 @@ func (p *Provider) getContractMetadata(ctx context.Context, contract persist.Eth return chainAgnosticContract, nil } -func (p *Provider) ownersToTokensForOwner(ctx context.Context, owner persist.Address, owners []Owner) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (p *Provider) ownersToTokensForOwner(ctx context.Context, owner persist.Address, owners []Owner) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { result := Token{} found := false for _, o := range owners { @@ -431,7 +431,7 @@ func (p *Provider) ownersToTokensForOwner(ctx context.Context, owner persist.Add return p.ownedTokensToChainAgnosticTokens(ctx, owner, []Token{result}) } -func (p *Provider) ownersToTokens(ctx context.Context, owners []Owner) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (p *Provider) ownersToTokens(ctx context.Context, owners []Owner) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { result := map[string]Token{} for _, o := range owners { @@ -447,8 +447,8 @@ func (p *Provider) ownersToTokens(ctx context.Context, owners []Owner) ([]multic } - agnosticTokens := []multichain.ChainAgnosticToken{} - agnosticContracts := []multichain.ChainAgnosticContract{} + agnosticTokens := []common.ChainAgnosticToken{} + agnosticContracts := []common.ChainAgnosticContract{} seenContracts := map[persist.Address]bool{} for owner, token := range result { a, c, err := p.ownedTokensToChainAgnosticTokens(ctx, persist.Address(strings.ToLower(owner)), []Token{token}) @@ -466,10 +466,10 @@ func (p *Provider) ownersToTokens(ctx context.Context, owners []Owner) ([]multic return agnosticTokens, agnosticContracts, nil } -func (p *Provider) ownedTokensToChainAgnosticTokens(ctx context.Context, owner persist.Address, tokens []Token) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (p *Provider) ownedTokensToChainAgnosticTokens(ctx context.Context, owner persist.Address, tokens []Token) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { - chainAgnosticTokens := []multichain.ChainAgnosticToken{} - chainAgnosticContracts := []multichain.ChainAgnosticContract{} + chainAgnosticTokens := []common.ChainAgnosticToken{} + chainAgnosticContracts := []common.ChainAgnosticContract{} seenContracts := map[persist.EthereumAddress]bool{} @@ -492,7 +492,7 @@ func (p *Provider) ownedTokensToChainAgnosticTokens(ctx context.Context, owner p return chainAgnosticTokens, chainAgnosticContracts, nil } -func ownedTokenToChainAgnosticToken(owner persist.Address, token Token) multichain.ChainAgnosticToken { +func ownedTokenToChainAgnosticToken(owner persist.Address, token Token) common.ChainAgnosticToken { var tokenType persist.TokenType switch token.TokenType { @@ -507,14 +507,14 @@ func ownedTokenToChainAgnosticToken(owner persist.Address, token Token) multicha b = big.NewInt(1) } - chainAgnosticToken := multichain.ChainAgnosticToken{ + chainAgnosticToken := common.ChainAgnosticToken{ TokenType: tokenType, TokenMetadata: persist.TokenMetadata(token.Metadata), TokenID: token.TokenID.ToTokenID(), OwnerAddress: owner, ContractAddress: persist.Address(token.Contract), Quantity: persist.HexString(b.Text(16)), - Descriptors: multichain.ChainAgnosticTokenDescriptors{ + Descriptors: common.ChainAgnosticTokenDescriptors{ Name: token.Name, }, } diff --git a/service/multichain/inject.go b/service/multichain/inject.go new file mode 100644 index 000000000..2e4cb61c6 --- /dev/null +++ b/service/multichain/inject.go @@ -0,0 +1,458 @@ +//go:build wireinject +// +build wireinject + +package multichain + +import ( + "context" + "database/sql" + "net/http" + + "github.com/ethereum/go-ethereum/ethclient" + "github.com/google/wire" + "github.com/jackc/pgx/v4/pgxpool" + + db "github.com/mikeydub/go-gallery/db/gen/coredb" + "github.com/mikeydub/go-gallery/service/eth" + "github.com/mikeydub/go-gallery/service/multichain/common" + "github.com/mikeydub/go-gallery/service/multichain/custom" + "github.com/mikeydub/go-gallery/service/multichain/poap" + "github.com/mikeydub/go-gallery/service/multichain/simplehash" + "github.com/mikeydub/go-gallery/service/multichain/tezos" + "github.com/mikeydub/go-gallery/service/multichain/wrapper" + "github.com/mikeydub/go-gallery/service/persist" + "github.com/mikeydub/go-gallery/service/persist/postgres" + "github.com/mikeydub/go-gallery/service/redis" + "github.com/mikeydub/go-gallery/service/rpc" + "github.com/mikeydub/go-gallery/service/rpc/arweave" + "github.com/mikeydub/go-gallery/service/rpc/ipfs" + "github.com/mikeydub/go-gallery/service/task" + "github.com/mikeydub/go-gallery/service/tokenmanage" + "github.com/mikeydub/go-gallery/util" +) + +// envInit is a type returned after setting up the environment +// Adding envInit as a dependency to a provider will ensure that the environment is set up prior +// to calling the provider +type envInit struct{} + +// NewMultichainProvider is a wire injector that sets up a multichain provider instance +func NewMultichainProvider(ctx context.Context, envFunc func()) (*Provider, func()) { + wire.Build( + setEnv, + wire.Value(http.DefaultClient), // HTTP client shared between providers + postgres.NewRepositories, + dbConnSet, + wire.Struct(new(ChainProvider), "*"), + tokenProcessingSubmitterInjector, + multichainProviderInjector, + ethInjector, + tezosInjector, + optimismInjector, + poapInjector, + zoraInjector, + baseInjector, + polygonInjector, + arbitrumInjector, + ) + return nil, nil +} + +// dbConnSet is a wire provider set for initializing a postgres connection +var dbConnSet = wire.NewSet( + newPqClient, + newPgxClient, + newQueries, +) + +func setEnv(f func()) envInit { + f() + return envInit{} +} + +func newPqClient(e envInit) (*sql.DB, func()) { + pq := postgres.MustCreateClient() + return pq, func() { pq.Close() } +} + +func newPgxClient(envInit) (*pgxpool.Pool, func()) { + pgx := postgres.NewPgxClient() + return pgx, func() { pgx.Close() } +} + +func newQueries(p *pgxpool.Pool) *db.Queries { + return db.New(p) +} + +func newTokenManageCache() *redis.Cache { + return redis.NewCache(redis.TokenManageCache) +} + +func multichainProviderInjector(ctx context.Context, repos *postgres.Repositories, q *db.Queries, chainProvider *ChainProvider, submitter *tokenmanage.TokenProcessingSubmitter) *Provider { + panic(wire.Build( + wire.Struct(new(Provider), "*"), + wire.Bind(new(tokenmanage.Submitter), util.ToPointer(submitter)), + newProviderLookup, + )) +} + +// New chains must be added here +func newProviderLookup(p *ChainProvider) ProviderLookup { + return ProviderLookup{ + persist.ChainETH: p.Ethereum, + persist.ChainTezos: p.Tezos, + persist.ChainOptimism: p.Optimism, + persist.ChainArbitrum: p.Arbitrum, + persist.ChainPOAP: p.Poap, + persist.ChainZora: p.Zora, + persist.ChainBase: p.Base, + persist.ChainPolygon: p.Polygon, + } +} + +func customMetadataHandlersInjector() *custom.CustomMetadataHandlers { + panic(wire.Build( + custom.NewCustomMetadataHandlers, + rpc.NewEthClient, + ipfs.NewShell, + arweave.NewClient, + )) +} + +func ethInjector(envInit, context.Context, *http.Client) (*EthereumProvider, func()) { + panic(wire.Build( + rpc.NewEthClient, + wire.Value(persist.ChainETH), + ethProviderInjector, + ethSyncPipelineInjector, + ethVerifierInjector, + simplehash.NewProvider, + )) +} + +func ethVerifierInjector(ethClient *ethclient.Client) *eth.Verifier { + panic(wire.Build(wire.Struct(new(eth.Verifier), "*"))) +} + +func ethProviderInjector( + ctx context.Context, + syncPipeline *wrapper.SyncPipelineWrapper, + verifier *eth.Verifier, + simplehashProvider *simplehash.Provider, +) *EthereumProvider { + panic(wire.Build( + wire.Struct(new(EthereumProvider), "*"), + wire.Bind(new(common.ContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokenMetadataBatcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokenMetadataFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensByContractWalletFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensByTokenIdentifiersFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensIncrementalContractFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.Verifier), util.ToPointer(verifier)), + )) +} + +func ethSyncPipelineInjector( + ctx context.Context, + httpClient *http.Client, + chain persist.Chain, + simplehashProvider *simplehash.Provider, +) (*wrapper.SyncPipelineWrapper, func()) { + panic(wire.Build( + wire.Struct(new(wrapper.SyncPipelineWrapper), "*"), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), + customMetadataHandlersInjector, + )) +} + +func tezosInjector(envInit, *http.Client) *TezosProvider { + wire.Build( + tezosProviderInjector, + wire.Value(persist.ChainTezos), + tezos.NewProvider, + simplehash.NewProvider, + ) + return nil +} + +func tezosProviderInjector(tezosProvider *tezos.Provider, simplehashProvider *simplehash.Provider) *TezosProvider { + panic(wire.Build( + wire.Struct(new(TezosProvider), "*"), + wire.Bind(new(common.Verifier), util.ToPointer(tezosProvider)), + wire.Bind(new(common.ContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenMetadataFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), + )) +} + +func optimismInjector(context.Context, *http.Client) (*OptimismProvider, func()) { + panic(wire.Build( + wire.Value(persist.ChainOptimism), + simplehash.NewProvider, + optimismProviderInjector, + optimismSyncPipelineInjector, + )) +} + +func optimismProviderInjector( + syncPipeline *wrapper.SyncPipelineWrapper, + simplehashProvider *simplehash.Provider, +) *OptimismProvider { + panic(wire.Build( + wire.Struct(new(OptimismProvider), "*"), + wire.Bind(new(common.ContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokenMetadataBatcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokenMetadataFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensByContractWalletFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensByTokenIdentifiersFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensIncrementalContractFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(syncPipeline)), + )) +} + +func optimismSyncPipelineInjector( + ctx context.Context, + httpClient *http.Client, + chain persist.Chain, + simplehashProvider *simplehash.Provider, +) (*wrapper.SyncPipelineWrapper, func()) { + panic(wire.Build( + wire.Struct(new(wrapper.SyncPipelineWrapper), "*"), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), + customMetadataHandlersInjector, + )) +} + +func arbitrumInjector(context.Context, *http.Client) (*ArbitrumProvider, func()) { + panic(wire.Build( + wire.Value(persist.ChainArbitrum), + simplehash.NewProvider, + arbitrumProviderInjector, + arbitrumSyncPipelineInjector, + )) +} + +func arbitrumProviderInjector( + syncPipeline *wrapper.SyncPipelineWrapper, + simplehashProvider *simplehash.Provider, +) *ArbitrumProvider { + panic(wire.Build( + wire.Struct(new(ArbitrumProvider), "*"), + wire.Bind(new(common.ContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokenMetadataBatcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokenMetadataFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensByTokenIdentifiersFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensByContractWalletFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensIncrementalContractFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(syncPipeline)), + )) +} + +func arbitrumSyncPipelineInjector( + ctx context.Context, + httpClient *http.Client, + chain persist.Chain, + simplehashProvider *simplehash.Provider, +) (*wrapper.SyncPipelineWrapper, func()) { + panic(wire.Build( + wire.Struct(new(wrapper.SyncPipelineWrapper), "*"), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), + customMetadataHandlersInjector, + )) +} + +func poapInjector(envInit, *http.Client) *PoapProvider { + panic(wire.Build( + poapProviderInjector, + poap.NewProvider, + )) +} + +func poapProviderInjector(poapProvider *poap.Provider) *PoapProvider { + panic(wire.Build( + wire.Struct(new(PoapProvider), "*"), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(poapProvider)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(poapProvider)), + wire.Bind(new(common.TokenMetadataFetcher), util.ToPointer(poapProvider)), + wire.Bind(new(common.TokenDescriptorsFetcher), util.ToPointer(poapProvider)), + )) +} + +func zoraInjector(envInit, context.Context, *http.Client) (*ZoraProvider, func()) { + panic(wire.Build( + wire.Value(persist.ChainZora), + simplehash.NewProvider, + zoraProviderInjector, + zoraSyncPipelineInjector, + )) +} + +func zoraProviderInjector( + syncPipeline *wrapper.SyncPipelineWrapper, + simplehashProvider *simplehash.Provider, +) *ZoraProvider { + panic(wire.Build( + wire.Struct(new(ZoraProvider), "*"), + wire.Bind(new(common.ContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokenMetadataBatcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokenMetadataFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensByContractWalletFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensByTokenIdentifiersFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensIncrementalContractFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(syncPipeline)), + )) +} + +func zoraSyncPipelineInjector( + ctx context.Context, + httpClient *http.Client, + chain persist.Chain, + simplehashProvider *simplehash.Provider, +) (*wrapper.SyncPipelineWrapper, func()) { + panic(wire.Build( + wire.Struct(new(wrapper.SyncPipelineWrapper), "*"), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), + customMetadataHandlersInjector, + )) +} + +func baseInjector(context.Context, *http.Client) (*BaseProvider, func()) { + panic(wire.Build( + wire.Value(persist.ChainBase), + simplehash.NewProvider, + baseProvidersInjector, + baseSyncPipelineInjector, + )) +} + +func baseProvidersInjector( + syncPipeline *wrapper.SyncPipelineWrapper, + simplehashProvider *simplehash.Provider, +) *BaseProvider { + panic(wire.Build( + wire.Struct(new(BaseProvider), "*"), + wire.Bind(new(common.ContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokenMetadataBatcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokenMetadataFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensByContractWalletFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensByTokenIdentifiersFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensIncrementalContractFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(syncPipeline)), + )) +} + +func baseSyncPipelineInjector( + ctx context.Context, + httpClient *http.Client, + chain persist.Chain, + simplehashProvider *simplehash.Provider, +) (*wrapper.SyncPipelineWrapper, func()) { + panic(wire.Build( + wire.Struct(new(wrapper.SyncPipelineWrapper), "*"), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), + customMetadataHandlersInjector, + )) +} + +func polygonInjector(context.Context, *http.Client) (*PolygonProvider, func()) { + panic(wire.Build( + wire.Value(persist.ChainPolygon), + simplehash.NewProvider, + polygonProvidersInjector, + polygonSyncPipelineInjector, + )) +} + +func polygonProvidersInjector( + syncPipeline *wrapper.SyncPipelineWrapper, + simplehashProvider *simplehash.Provider, +) *PolygonProvider { + panic(wire.Build( + wire.Struct(new(PolygonProvider), "*"), + wire.Bind(new(common.ContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensIncrementalContractFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokenMetadataBatcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensByContractWalletFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokensByTokenIdentifiersFetcher), util.ToPointer(syncPipeline)), + wire.Bind(new(common.TokenDescriptorsFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenMetadataFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.ContractsCreatorFetcher), util.ToPointer(simplehashProvider)), + )) +} + +func polygonSyncPipelineInjector( + ctx context.Context, + httpClient *http.Client, + chain persist.Chain, + simplehashProvider *simplehash.Provider, +) (*wrapper.SyncPipelineWrapper, func()) { + panic(wire.Build( + wire.Struct(new(wrapper.SyncPipelineWrapper), "*"), + wire.Bind(new(common.TokenIdentifierOwnerFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalOwnerFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensIncrementalContractFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokenMetadataBatcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByContractWalletFetcher), util.ToPointer(simplehashProvider)), + wire.Bind(new(common.TokensByTokenIdentifiersFetcher), util.ToPointer(simplehashProvider)), + customMetadataHandlersInjector, + )) +} + +func tokenProcessingSubmitterInjector(context.Context) *tokenmanage.TokenProcessingSubmitter { + panic(wire.Build( + wire.Struct(new(tokenmanage.TokenProcessingSubmitter), "*"), + task.NewClient, + wire.Struct(new(tokenmanage.Registry), "*"), + newTokenManageCache, + )) +} diff --git a/service/multichain/multichain.go b/service/multichain/multichain.go index 9738653b5..691b35b80 100644 --- a/service/multichain/multichain.go +++ b/service/multichain/multichain.go @@ -20,6 +20,7 @@ import ( "github.com/mikeydub/go-gallery/platform" "github.com/mikeydub/go-gallery/service/logger" "github.com/mikeydub/go-gallery/service/media" + common "github.com/mikeydub/go-gallery/service/multichain/common" op "github.com/mikeydub/go-gallery/service/multichain/operation" "github.com/mikeydub/go-gallery/service/persist" "github.com/mikeydub/go-gallery/service/persist/postgres" @@ -49,75 +50,11 @@ type Provider struct { Submitter tokenmanage.Submitter } -// ChainAgnosticToken is a token that is agnostic to the chain it is on -type ChainAgnosticToken struct { - Descriptors ChainAgnosticTokenDescriptors `json:"descriptors"` - TokenType persist.TokenType `json:"token_type"` - TokenURI persist.TokenURI `json:"token_uri"` - TokenID persist.HexTokenID `json:"token_id"` - Quantity persist.HexString `json:"quantity"` - OwnerAddress persist.Address `json:"owner_address"` - TokenMetadata persist.TokenMetadata `json:"metadata"` - ContractAddress persist.Address `json:"contract_address"` - FallbackMedia persist.FallbackMedia `json:"fallback_media"` - ExternalURL string `json:"external_url"` - BlockNumber persist.BlockNumber `json:"block_number"` - IsSpam *bool `json:"is_spam"` -} - -// ChainAgnosticContract is a contract that is agnostic to the chain it is on -type ChainAgnosticContract struct { - Descriptors ChainAgnosticContractDescriptors `json:"descriptors"` - Address persist.Address `json:"address"` - IsSpam *bool `json:"is_spam"` - LatestBlock persist.BlockNumber `json:"latest_block"` -} - -type ChainAgnosticTokensAndContracts struct { - Tokens []ChainAgnosticToken `json:"tokens"` - Contracts []ChainAgnosticContract `json:"contracts"` -} - -// ChainAgnosticTokenDescriptors are the fields that describe a token but cannot be used to uniquely identify it -type ChainAgnosticTokenDescriptors struct { - Name string `json:"name"` - Description string `json:"description"` -} - -type ChainAgnosticContractDescriptors struct { - Symbol string `json:"symbol"` - Name string `json:"name"` - Description string `json:"description"` - ProfileImageURL string `json:"profile_image_url"` - OwnerAddress persist.Address `json:"owner_address"` -} - -// ChainAgnosticIdentifiers identify tokens despite their chain -type ChainAgnosticIdentifiers struct { - ContractAddress persist.Address `json:"contract_address"` - TokenID persist.HexTokenID `json:"token_id"` -} - -func (t ChainAgnosticIdentifiers) String() string { - return fmt.Sprintf("token(address=%s, tokenID=%s)", t.ContractAddress, t.TokenID.ToDecimalTokenID()) -} - type ErrProviderFailed struct{ Err error } func (e ErrProviderFailed) Unwrap() error { return e.Err } func (e ErrProviderFailed) Error() string { return fmt.Sprintf("calling provider failed: %s", e.Err) } -type ErrProviderContractNotFound struct { - Contract persist.Address - Chain persist.Chain - Err error -} - -func (e ErrProviderContractNotFound) Unwrap() error { return e.Err } -func (e ErrProviderContractNotFound) Error() string { - return fmt.Sprintf("provider did not find contract: %s", e.Contract.String()) -} - type communityInfo interface { GetKey() persist.CommunityKey GetName() string @@ -127,61 +64,10 @@ type communityInfo interface { GetWebsiteURL() string } -// Verifier can verify that a signature is signed by a given key -type Verifier interface { - VerifySignature(ctx context.Context, pubKey persist.PubKey, walletType persist.WalletType, nonce string, sig string) (bool, error) -} - -type TokenIdentifierOwnerFetcher interface { - GetTokenByTokenIdentifiersAndOwner(context.Context, ChainAgnosticIdentifiers, persist.Address) (ChainAgnosticToken, ChainAgnosticContract, error) -} - -type TokensByContractWalletFetcher interface { - GetTokensByContractWallet(ctx context.Context, contract persist.ChainAddress, wallet persist.Address) ([]ChainAgnosticToken, ChainAgnosticContract, error) -} - -type TokensByTokenIdentifiersFetcher interface { - GetTokensByTokenIdentifiers(context.Context, ChainAgnosticIdentifiers) ([]ChainAgnosticToken, ChainAgnosticContract, error) -} - -// TokensIncrementalOwnerFetcher supports fetching tokens for syncing incrementally -type TokensIncrementalOwnerFetcher interface { - // NOTE: implementation MUST close the rec channel - GetTokensIncrementallyByWalletAddress(ctx context.Context, address persist.Address) (<-chan ChainAgnosticTokensAndContracts, <-chan error) -} - -// TokensIncrementalContractFetcher supports fetching tokens by contract for syncing incrementally -type TokensIncrementalContractFetcher interface { - // NOTE: implementations MUST close the rec channel - // maxLimit is not for pagination, it is to make sure we don't fetch a bajilion tokens from an omnibus contract - GetTokensIncrementallyByContractAddress(ctx context.Context, address persist.Address, maxLimit int) (<-chan ChainAgnosticTokensAndContracts, <-chan error) -} - -type ContractFetcher interface { - GetContractByAddress(ctx context.Context, contract persist.Address) (ChainAgnosticContract, error) -} - -type ContractsCreatorFetcher interface { - GetContractsByCreatorAddress(ctx context.Context, owner persist.Address) ([]ChainAgnosticContract, error) -} - -// TokenMetadataFetcher supports fetching token metadata -type TokenMetadataFetcher interface { - GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti ChainAgnosticIdentifiers) (persist.TokenMetadata, error) -} - -type TokenMetadataBatcher interface { - GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, tIDs []ChainAgnosticIdentifiers) ([]persist.TokenMetadata, error) -} - -type TokenDescriptorsFetcher interface { - GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, ti ChainAgnosticIdentifiers) (ChainAgnosticTokenDescriptors, ChainAgnosticContractDescriptors, error) -} - type chainTokensAndContracts struct { Chain persist.Chain - Tokens []ChainAgnosticToken - Contracts []ChainAgnosticContract + Tokens []common.ChainAgnosticToken + Contracts []common.ChainAgnosticContract } // SyncTokensByUserID updates the media for all tokens for a user @@ -203,7 +89,7 @@ func (p *Provider) SyncTokensByUserID(ctx context.Context, userID persist.DBID, wg := &conc.WaitGroup{} for c, a := range chainsToAddresses { - fetcher, ok := p.Chains[c].(TokensIncrementalOwnerFetcher) + fetcher, ok := p.Chains[c].(common.TokensIncrementalOwnerFetcher) if !ok { continue } @@ -265,8 +151,8 @@ func (p *Provider) SyncCreatedTokensForNewContracts(ctx context.Context, userID wg := &conc.WaitGroup{} for c, a := range chainsToAddresses { - contractFetcher, contractOK := p.Chains[c].(ContractsCreatorFetcher) - tokenFetcher, tokenOK := p.Chains[c].(TokensIncrementalContractFetcher) + contractFetcher, contractOK := p.Chains[c].(common.ContractsCreatorFetcher) + tokenFetcher, tokenOK := p.Chains[c].(common.TokensIncrementalContractFetcher) if !contractOK || !tokenOK { continue @@ -356,7 +242,7 @@ func (p *Provider) AddTokensToUserUnchecked(ctx context.Context, userID persist. outer: for _, t := range tIDs { // Validate that the chain is supported - _, ok := p.Chains[t.Chain].(TokensByTokenIdentifiersFetcher) + _, ok := p.Chains[t.Chain].(common.TokensByTokenIdentifiersFetcher) if !ok { err = fmt.Errorf("multichain is not configured to fetch unchecked tokens for chain=%s", t.Chain) logger.For(ctx).Error(err) @@ -368,8 +254,8 @@ outer: if _, ok := chainPages[t.Chain]; !ok { chainPages[t.Chain] = chainTokensAndContracts{ Chain: t.Chain, - Tokens: make([]ChainAgnosticToken, 0), - Contracts: make([]ChainAgnosticContract, 0), + Tokens: make([]common.ChainAgnosticToken, 0), + Contracts: make([]common.ChainAgnosticContract, 0), } } continue outer @@ -382,9 +268,9 @@ outer: } for i, t := range tIDs { - tokenID := ChainAgnosticIdentifiers{ContractAddress: t.ContractAddress, TokenID: t.TokenID} + tokenID := common.ChainAgnosticIdentifiers{ContractAddress: t.ContractAddress, TokenID: t.TokenID} - tokens, contract, err := p.Chains[t.Chain].(TokensByTokenIdentifiersFetcher).GetTokensByTokenIdentifiers(ctx, tokenID) + tokens, contract, err := p.Chains[t.Chain].(common.TokensByTokenIdentifiersFetcher).GetTokensByTokenIdentifiers(ctx, tokenID) // Exit early if a token in the batch is not found if err != nil { err := fmt.Errorf("failed to fetch token(chain=%s, contract=%s, tokenID=%s): %s", t.Chain, t.ContractAddress, t.TokenID, err) @@ -469,7 +355,7 @@ func (p *Provider) SyncTokensByUserIDAndTokenIdentifiers(ctx context.Context, us chain := c tids := t - fetcher, ok := p.Chains[chain].(TokenIdentifierOwnerFetcher) + fetcher, ok := p.Chains[chain].(common.TokenIdentifierOwnerFetcher) if !ok { continue } @@ -478,7 +364,7 @@ func (p *Provider) SyncTokensByUserIDAndTokenIdentifiers(ctx context.Context, us tid := tid wg.Go(func() { logger.For(ctx).Infof("syncing chain=%s; user=%s; token=%s", chain, user.Username.String(), tid) - id := ChainAgnosticIdentifiers{ContractAddress: tid.ContractAddress, TokenID: tid.TokenID} + id := common.ChainAgnosticIdentifiers{ContractAddress: tid.ContractAddress, TokenID: tid.TokenID} token, contract, err := fetcher.GetTokenByTokenIdentifiersAndOwner(ctx, id, tid.OwnerAddress) if err != nil { errCh <- ErrProviderFailed{Err: err} @@ -486,8 +372,8 @@ func (p *Provider) SyncTokensByUserIDAndTokenIdentifiers(ctx context.Context, us } recCh <- chainTokensAndContracts{ Chain: chain, - Tokens: []ChainAgnosticToken{token}, - Contracts: []ChainAgnosticContract{contract}, + Tokens: []common.ChainAgnosticToken{token}, + Contracts: []common.ChainAgnosticContract{contract}, } }) } @@ -588,7 +474,7 @@ func (p *Provider) SyncCreatedTokensForExistingContract(ctx context.Context, use return err } - f, ok := p.Chains[contract.Chain].(TokensIncrementalContractFetcher) + f, ok := p.Chains[contract.Chain].(common.TokensIncrementalContractFetcher) if !ok { return fmt.Errorf("no tokens contract fetcher for chain: %s", contract.Chain) } @@ -635,7 +521,7 @@ func (p *Provider) processCommunities(ctx context.Context, contracts []db.Contra return p.processArtBlocksCommunityTokens(ctx, knownProviders, tokens) } -func (p *Provider) processTokensForUsers(ctx context.Context, chain persist.Chain, users map[persist.DBID]persist.User, chainTokensForUsers map[persist.DBID][]ChainAgnosticToken, contracts []db.Contract, upsertParams op.TokenUpsertParams) (newUserTokens map[persist.DBID][]op.TokenFullDetails, err error) { +func (p *Provider) processTokensForUsers(ctx context.Context, chain persist.Chain, users map[persist.DBID]persist.User, chainTokensForUsers map[persist.DBID][]common.ChainAgnosticToken, contracts []db.Contract, upsertParams op.TokenUpsertParams) (newUserTokens map[persist.DBID][]op.TokenFullDetails, err error) { definitionsToAdd := make([]db.TokenDefinition, 0) tokensToAdd := make([]op.UpsertToken, 0) @@ -736,9 +622,9 @@ func (p *Provider) processTokensForUsers(ctx context.Context, chain persist.Chai return newUserTokens, err } -type addTokensFunc func(context.Context, persist.User, persist.Chain, []ChainAgnosticToken, []db.Contract) (newTokens []op.TokenFullDetails, err error) +type addTokensFunc func(context.Context, persist.User, persist.Chain, []common.ChainAgnosticToken, []db.Contract) (newTokens []op.TokenFullDetails, err error) -func (p *Provider) addCreatorTokensOfContractsToUser(ctx context.Context, user persist.User, chain persist.Chain, tokens []ChainAgnosticToken, contracts []db.Contract) (newTokens []op.TokenFullDetails, err error) { +func (p *Provider) addCreatorTokensOfContractsToUser(ctx context.Context, user persist.User, chain persist.Chain, tokens []common.ChainAgnosticToken, contracts []db.Contract) (newTokens []op.TokenFullDetails, err error) { return p.processTokensForUser(ctx, user, chain, tokens, contracts, op.TokenUpsertParams{ SetCreatorFields: true, SetHolderFields: false, @@ -746,7 +632,7 @@ func (p *Provider) addCreatorTokensOfContractsToUser(ctx context.Context, user p }) } -func (p *Provider) addHolderTokensToUser(ctx context.Context, user persist.User, chain persist.Chain, tokens []ChainAgnosticToken, contracts []db.Contract) (newTokens []op.TokenFullDetails, err error) { +func (p *Provider) addHolderTokensToUser(ctx context.Context, user persist.User, chain persist.Chain, tokens []common.ChainAgnosticToken, contracts []db.Contract) (newTokens []op.TokenFullDetails, err error) { return p.processTokensForUser(ctx, user, chain, tokens, contracts, op.TokenUpsertParams{ SetCreatorFields: false, SetHolderFields: true, @@ -754,9 +640,9 @@ func (p *Provider) addHolderTokensToUser(ctx context.Context, user persist.User, }) } -func (p *Provider) processTokensForUser(ctx context.Context, user persist.User, chain persist.Chain, tokens []ChainAgnosticToken, contracts []db.Contract, upsertParams op.TokenUpsertParams) (newTokens []op.TokenFullDetails, error error) { +func (p *Provider) processTokensForUser(ctx context.Context, user persist.User, chain persist.Chain, tokens []common.ChainAgnosticToken, contracts []db.Contract, upsertParams op.TokenUpsertParams) (newTokens []op.TokenFullDetails, error error) { userMap := map[persist.DBID]persist.User{user.ID: user} - providerTokenMap := map[persist.DBID][]ChainAgnosticToken{user.ID: tokens} + providerTokenMap := map[persist.DBID][]common.ChainAgnosticToken{user.ID: tokens} newUserTokens, err := p.processTokensForUsers(ctx, chain, userMap, providerTokenMap, contracts, upsertParams) if err != nil { return nil, err @@ -890,7 +776,7 @@ func (p *Provider) GetTokensOfContractForWallet(ctx context.Context, contractAdd return nil, fmt.Errorf("user does not own wallet with address: %s", wallet) } - f, ok := p.Chains[contractAddress.Chain()].(TokensByContractWalletFetcher) + f, ok := p.Chains[contractAddress.Chain()].(common.TokensByContractWalletFetcher) if !ok { return nil, fmt.Errorf("no tokens owner fetcher for chain: %s", contractAddress.Chain()) } @@ -909,7 +795,7 @@ func (p *Provider) GetTokensOfContractForWallet(ctx context.Context, contractAdd outCh <- chainTokensAndContracts{ Chain: contractAddress.Chain(), Tokens: tokens, - Contracts: []ChainAgnosticContract{contract}, + Contracts: []common.ChainAgnosticContract{contract}, } }() @@ -940,8 +826,8 @@ func (p *Provider) GetTokensOfContractForWallet(ctx context.Context, contractAdd return ownedTokens, nil } -func (p *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, chain persist.Chain, tIDs []ChainAgnosticIdentifiers) ([]persist.TokenMetadata, error) { - f, ok := p.Chains[chain].(TokenMetadataBatcher) +func (p *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, chain persist.Chain, tIDs []common.ChainAgnosticIdentifiers) ([]persist.TokenMetadata, error) { + f, ok := p.Chains[chain].(common.TokenMetadataBatcher) if !ok { return nil, fmt.Errorf("no metadata batchers for chain %s", chain) } @@ -949,16 +835,16 @@ func (p *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, } func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, contractAddress persist.Address, tokenID persist.HexTokenID, chain persist.Chain) (persist.TokenMetadata, error) { - fetcher, ok := p.Chains[chain].(TokenMetadataFetcher) + fetcher, ok := p.Chains[chain].(common.TokenMetadataFetcher) if !ok { return nil, fmt.Errorf("no metadata fetchers for chain %s", chain) } - return fetcher.GetTokenMetadataByTokenIdentifiers(ctx, ChainAgnosticIdentifiers{ContractAddress: contractAddress, TokenID: tokenID}) + return fetcher.GetTokenMetadataByTokenIdentifiers(ctx, common.ChainAgnosticIdentifiers{ContractAddress: contractAddress, TokenID: tokenID}) } // VerifySignature verifies a signature for a wallet address func (p *Provider) VerifySignature(ctx context.Context, pSig string, pMessage string, pChainAddress persist.ChainPubKey, pWalletType persist.WalletType) (bool, error) { - if verifier, ok := p.Chains[pChainAddress.Chain()].(Verifier); ok { + if verifier, ok := p.Chains[pChainAddress.Chain()].(common.Verifier); ok { if valid, err := verifier.VerifySignature(ctx, pChainAddress.PubKey(), pWalletType, pMessage, pSig); err != nil || !valid { return false, err } @@ -1001,12 +887,12 @@ func (p *Provider) RefreshToken(ctx context.Context, ti persist.TokenIdentifiers // RefreshTokenDescriptorsByTokenIdentifiers will refresh the token descriptors for a token by its identifiers. func (p *Provider) RefreshTokenDescriptorsByTokenIdentifiers(ctx context.Context, ti persist.TokenIdentifiers) (db.TokenDefinition, error) { - fetcher, ok := p.Chains[ti.Chain].(TokenDescriptorsFetcher) + fetcher, ok := p.Chains[ti.Chain].(common.TokenDescriptorsFetcher) if !ok { return db.TokenDefinition{}, fmt.Errorf("no token descriptor fetchers for chain %s", ti.Chain) } - id := ChainAgnosticIdentifiers{ContractAddress: ti.ContractAddress, TokenID: ti.TokenID} + id := common.ChainAgnosticIdentifiers{ContractAddress: ti.ContractAddress, TokenID: ti.TokenID} var t db.TokenDefinition var c db.Contract @@ -1049,9 +935,9 @@ func (p *Provider) RefreshTokenDescriptorsByTokenIdentifiers(ctx context.Context // RefreshContract refreshes a contract on the given chain using the chain provider for that chain func (p *Provider) RefreshContract(ctx context.Context, ci persist.ContractIdentifiers) error { - var contracts []ChainAgnosticContract + var contracts []common.ChainAgnosticContract - if fetcher, ok := p.Chains[ci.Chain].(ContractFetcher); ok { + if fetcher, ok := p.Chains[ci.Chain].(common.ContractFetcher); ok { c, err := fetcher.GetContractByAddress(ctx, ci.ContractAddress) if err != nil { return err @@ -1064,7 +950,7 @@ func (p *Provider) RefreshContract(ctx context.Context, ci persist.ContractIdent } type ContractOwnerResult struct { - Contracts []ChainAgnosticContract + Contracts []common.ChainAgnosticContract Chain persist.Chain } @@ -1191,7 +1077,7 @@ func (d *Provider) processContractCommunities(ctx context.Context, contracts []d // processContracts deduplicates contracts and upserts them into the database. If canOverwriteOwnerAddress is true, then // the owner address of an existing contract will be overwritten if the new contract provides a non-empty owner address. // An empty owner address will never overwrite an existing address, even if canOverwriteOwnerAddress is true. -func (d *Provider) processContracts(ctx context.Context, chain persist.Chain, contracts []ChainAgnosticContract, canOverwriteOwnerAddress bool) (newContracts []db.Contract, err error) { +func (d *Provider) processContracts(ctx context.Context, chain persist.Chain, contracts []common.ChainAgnosticContract, canOverwriteOwnerAddress bool) (newContracts []db.Contract, err error) { contractsToAdd := chainContractsToUpsertableContracts(chain, contracts) addedContracts, err := d.Repos.ContractRepository.BulkUpsert(ctx, contractsToAdd, canOverwriteOwnerAddress) @@ -1208,7 +1094,7 @@ func (d *Provider) processContracts(ctx context.Context, chain persist.Chain, co } // chainTokensToUpsertableTokenDefinitions returns a slice of token definitions that are ready to be upserted into the database from a slice of chainTokens. -func chainTokensToUpsertableTokenDefinitions(ctx context.Context, chain persist.Chain, tokens []ChainAgnosticToken, existingContracts []db.Contract) []db.TokenDefinition { +func chainTokensToUpsertableTokenDefinitions(ctx context.Context, chain persist.Chain, tokens []common.ChainAgnosticToken, existingContracts []db.Contract) []db.TokenDefinition { result := make(map[persist.TokenIdentifiers]db.TokenDefinition) contracts := make(map[persist.ChainAddress]db.Contract) for _, c := range existingContracts { @@ -1233,7 +1119,7 @@ func chainTokensToUpsertableTokenDefinitions(ctx context.Context, chain persist. return util.MapValues(result) } -func tokenToTokenDefinitionDB(t ChainAgnosticToken, c db.Contract) db.TokenDefinition { +func tokenToTokenDefinitionDB(t common.ChainAgnosticToken, c db.Contract) db.TokenDefinition { return db.TokenDefinition{ Name: util.ToNullString(t.Descriptors.Name, true), Description: util.ToNullString(t.Descriptors.Description, true), @@ -1264,7 +1150,7 @@ func mergeTokenDefinitions(a db.TokenDefinition, b db.TokenDefinition) db.TokenD } // chainTokensToUpsertableTokens returns a unique slice of tokens that are ready to be upserted into the database. -func chainTokensToUpsertableTokens(chain persist.Chain, tokens []ChainAgnosticToken, existingContracts []db.Contract, ownerUser persist.User) []op.UpsertToken { +func chainTokensToUpsertableTokens(chain persist.Chain, tokens []common.ChainAgnosticToken, existingContracts []db.Contract, ownerUser persist.User) []op.UpsertToken { addressToContract := make(map[string]db.Contract) util.Map(existingContracts, func(c db.Contract) (any, error) { @@ -1371,7 +1257,7 @@ func chainTokensToUpsertableTokens(chain persist.Chain, tokens []ChainAgnosticTo } // contractsToUpsertableContracts returns a unique slice of contracts that are ready to be upserted into the database. -func chainContractsToUpsertableContracts(chain persist.Chain, contracts []ChainAgnosticContract) []db.Contract { +func chainContractsToUpsertableContracts(chain persist.Chain, contracts []common.ChainAgnosticContract) []db.Contract { result := map[persist.Address]db.Contract{} for _, c := range contracts { normalizedAddress := persist.Address(chain.NormalizeAddress(c.Address)) diff --git a/service/multichain/objkt/objkt.go b/service/multichain/objkt/objkt.go index e174b1fa7..5b6b98ef8 100644 --- a/service/multichain/objkt/objkt.go +++ b/service/multichain/objkt/objkt.go @@ -7,7 +7,7 @@ import ( "strconv" "github.com/mikeydub/go-gallery/service/logger" - "github.com/mikeydub/go-gallery/service/multichain" + "github.com/mikeydub/go-gallery/service/multichain/common" "github.com/mikeydub/go-gallery/service/multichain/tezos" "github.com/mikeydub/go-gallery/service/persist" "github.com/mikeydub/go-gallery/util" @@ -102,7 +102,7 @@ func NewProvider() *Provider { } } -func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { +func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { t, _, err := p.GetTokensByTokenIdentifiers(ctx, ti) if err != nil { return persist.TokenMetadata{}, err @@ -115,7 +115,7 @@ func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti mu return t[0].TokenMetadata, nil } -func (p *Provider) GetTokensByWalletAddress(ctx context.Context, ownerAddress persist.Address) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByWalletAddress(ctx context.Context, ownerAddress persist.Address) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { ctx = logger.NewContextWithFields(ctx, logrus.Fields{"ownerAddress": ownerAddress}) tzOwnerAddress, err := tezos.ToAddress(ownerAddress) if err != nil { @@ -154,10 +154,10 @@ func (p *Provider) GetTokensByWalletAddress(ctx context.Context, ownerAddress pe return returnTokens, returnContracts, nil } -func objktTokensToChainAgnostic(tokens []tokenNode, tzOwnerAddress persist.Address) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract) { - returnTokens := make([]multichain.ChainAgnosticToken, 0, len(tokens)) - returnContracts := make([]multichain.ChainAgnosticContract, 0) - dedupeContracts := make(map[persist.Address]multichain.ChainAgnosticContract) +func objktTokensToChainAgnostic(tokens []tokenNode, tzOwnerAddress persist.Address) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract) { + returnTokens := make([]common.ChainAgnosticToken, 0, len(tokens)) + returnContracts := make([]common.ChainAgnosticContract, 0) + dedupeContracts := make(map[persist.Address]common.ChainAgnosticContract) for _, node := range tokens { @@ -168,9 +168,9 @@ func objktTokensToChainAgnostic(tokens []tokenNode, tzOwnerAddress persist.Addre metadata := createMetadata(node.Token) if _, ok := dedupeContracts[node.Token.Fa.Contract]; !ok { - dedupeContracts[node.Token.Fa.Contract] = multichain.ChainAgnosticContract{ + dedupeContracts[node.Token.Fa.Contract] = common.ChainAgnosticContract{ Address: node.Token.Fa.Contract, - Descriptors: multichain.ChainAgnosticContractDescriptors{ + Descriptors: common.ChainAgnosticContractDescriptors{ Symbol: node.Token.Symbol, Name: node.Token.Fa.Name, Description: node.Token.Fa.Description, @@ -185,9 +185,9 @@ func objktTokensToChainAgnostic(tokens []tokenNode, tzOwnerAddress persist.Addre tokenID := persist.MustTokenID(string(node.Token.Token_ID)) - agnosticToken := multichain.ChainAgnosticToken{ + agnosticToken := common.ChainAgnosticToken{ TokenType: persist.TokenTypeERC1155, - Descriptors: multichain.ChainAgnosticTokenDescriptors{ + Descriptors: common.ChainAgnosticTokenDescriptors{ Description: node.Token.Description, Name: node.Token.Name, }, @@ -204,8 +204,8 @@ func objktTokensToChainAgnostic(tokens []tokenNode, tzOwnerAddress persist.Addre return returnTokens, returnContracts } -func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ownerAddress persist.Address) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { - recCh := make(chan multichain.ChainAgnosticTokensAndContracts) +func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ownerAddress persist.Address) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + recCh := make(chan common.ChainAgnosticTokensAndContracts) errCh := make(chan error) go func() { defer close(recCh) @@ -240,7 +240,7 @@ func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ow returnTokens, returnContracts := objktTokensToChainAgnostic(query.Holder[0].Held_Tokens, tzOwnerAddress) - recCh <- multichain.ChainAgnosticTokensAndContracts{ + recCh <- common.ChainAgnosticTokensAndContracts{ Tokens: returnTokens, Contracts: returnContracts, } @@ -251,7 +251,7 @@ func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ow return recCh, errCh } -func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, tokenIdentifiers multichain.ChainAgnosticIdentifiers, ownerAddress persist.Address) (multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, tokenIdentifiers common.ChainAgnosticIdentifiers, ownerAddress persist.Address) (common.ChainAgnosticToken, common.ChainAgnosticContract, error) { ctx = logger.NewContextWithFields(ctx, logrus.Fields{ "contractAddress": tokenIdentifiers.ContractAddress, "tokenID": tokenIdentifiers.TokenID, @@ -260,12 +260,12 @@ func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, token tzOwnerAddress, err := tezos.ToAddress(ownerAddress) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } tokenInDecimal, err := strconv.ParseInt(tokenIdentifiers.TokenID.String(), 16, 64) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } var query tokensByIdentifiersOwnerQuery @@ -275,20 +275,20 @@ func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, token "ownerAddress": graphql.String(tzOwnerAddress), "tokenID": graphql.String(strconv.Itoa(int(tokenInDecimal))), }); err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } if len(query.Token) < 1 { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, fmt.Errorf("no token found for token identifiers: %s", tokenIdentifiers.String()) + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, fmt.Errorf("no token found for token identifiers: %s", tokenIdentifiers.String()) } token := query.Token[0] metadata := createMetadata(token) - agnosticContract := multichain.ChainAgnosticContract{ + agnosticContract := common.ChainAgnosticContract{ Address: token.Fa.Contract, - Descriptors: multichain.ChainAgnosticContractDescriptors{ + Descriptors: common.ChainAgnosticContractDescriptors{ Symbol: token.Symbol, Name: token.Fa.Name, Description: token.Fa.Description, @@ -300,9 +300,9 @@ func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, token tokenID := persist.MustTokenID(string(token.Token_ID)) - agnosticToken := multichain.ChainAgnosticToken{ + agnosticToken := common.ChainAgnosticToken{ TokenType: persist.TokenTypeERC1155, - Descriptors: multichain.ChainAgnosticTokenDescriptors{ + Descriptors: common.ChainAgnosticTokenDescriptors{ Description: token.Description, Name: token.Name, }, @@ -317,7 +317,7 @@ func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, token return agnosticToken, agnosticContract, nil } -func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentifiers multichain.ChainAgnosticIdentifiers) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentifiers common.ChainAgnosticIdentifiers) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { ctx = logger.NewContextWithFields(ctx, logrus.Fields{ "contractAddress": tokenIdentifiers.ContractAddress, "tokenID": tokenIdentifiers.TokenID, @@ -325,7 +325,7 @@ func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentif tokenInDecimal, err := strconv.ParseInt(tokenIdentifiers.TokenID.String(), 16, 64) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } var query tokensByIdentifiersQuery @@ -334,18 +334,18 @@ func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentif "contractAddress": graphql.String(tokenIdentifiers.ContractAddress), "tokenID": graphql.String(strconv.Itoa(int(tokenInDecimal))), }); err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } if len(query.Token) < 1 { - return nil, multichain.ChainAgnosticContract{}, fmt.Errorf("no token found for token identifiers: %s", tokenIdentifiers.String()) + return nil, common.ChainAgnosticContract{}, fmt.Errorf("no token found for token identifiers: %s", tokenIdentifiers.String()) } firstToken := query.Token[0] - agnosticContract := multichain.ChainAgnosticContract{ + agnosticContract := common.ChainAgnosticContract{ Address: firstToken.Fa.Contract, - Descriptors: multichain.ChainAgnosticContractDescriptors{ + Descriptors: common.ChainAgnosticContractDescriptors{ Symbol: firstToken.Symbol, Name: firstToken.Name, Description: firstToken.Description, @@ -358,7 +358,7 @@ func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentif return objktHolderTokensToChainAgnostic(query.Token), agnosticContract, nil } -func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, maxLimit, offset int) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, maxLimit, offset int) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { ctx = logger.NewContextWithFields(ctx, logrus.Fields{"contractAddress": contractAddress}) pageSize := maxPageSize @@ -375,7 +375,7 @@ func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddre "limit": graphql.Int(pageSize), "offset": graphql.Int(offset), }); err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } // No more results @@ -394,7 +394,7 @@ func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddre // No matching query results if len(tokens) < 1 { - return nil, multichain.ChainAgnosticContract{}, fmt.Errorf("no tokens found for contract") + return nil, common.ChainAgnosticContract{}, fmt.Errorf("no tokens found for contract") } // Truncate tokens if there is a max limit @@ -402,9 +402,9 @@ func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddre tokens = tokens[:maxLimit] } - agnosticContract := multichain.ChainAgnosticContract{ + agnosticContract := common.ChainAgnosticContract{ Address: tokens[0].Fa.Contract, - Descriptors: multichain.ChainAgnosticContractDescriptors{ + Descriptors: common.ChainAgnosticContractDescriptors{ Symbol: tokens[0].Symbol, Name: tokens[0].Fa.Name, Description: tokens[0].Fa.Description, @@ -417,8 +417,8 @@ func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddre return objktHolderTokensToChainAgnostic(tokens), agnosticContract, nil } -func objktHolderTokensToChainAgnostic(tokens []token) []multichain.ChainAgnosticToken { - result := make([]multichain.ChainAgnosticToken, 0, len(tokens)) +func objktHolderTokensToChainAgnostic(tokens []token) []common.ChainAgnosticToken { + result := make([]common.ChainAgnosticToken, 0, len(tokens)) for _, token := range tokens { tokenID := persist.MustTokenID(string(token.Token_ID)) metadata := createMetadata(token) @@ -428,9 +428,9 @@ func objktHolderTokensToChainAgnostic(tokens []token) []multichain.ChainAgnostic }) for _, holder := range token.Holders { - agnosticToken := multichain.ChainAgnosticToken{ + agnosticToken := common.ChainAgnosticToken{ TokenType: persist.TokenTypeERC1155, - Descriptors: multichain.ChainAgnosticTokenDescriptors{ + Descriptors: common.ChainAgnosticTokenDescriptors{ Description: token.Description, Name: token.Name, }, diff --git a/service/multichain/opensea/opensea.go b/service/multichain/opensea/opensea.go index f13837579..b5ed1af7f 100644 --- a/service/multichain/opensea/opensea.go +++ b/service/multichain/opensea/opensea.go @@ -18,7 +18,7 @@ import ( "github.com/mikeydub/go-gallery/env" "github.com/mikeydub/go-gallery/service/eth" "github.com/mikeydub/go-gallery/service/logger" - "github.com/mikeydub/go-gallery/service/multichain" + "github.com/mikeydub/go-gallery/service/multichain/common" "github.com/mikeydub/go-gallery/service/persist" sentryutil "github.com/mikeydub/go-gallery/service/sentry" "github.com/mikeydub/go-gallery/util" @@ -111,7 +111,7 @@ func NewProvider(ctx context.Context, httpClient *http.Client, chain persist.Cha } // GetTokensByWalletAddress returns a list of tokens for an address -func (p *Provider) GetTokensByWalletAddress(ctx context.Context, ownerAddress persist.Address) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByWalletAddress(ctx context.Context, ownerAddress persist.Address) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { outCh := make(chan assetsReceived) go func() { defer close(outCh) @@ -121,8 +121,8 @@ func (p *Provider) GetTokensByWalletAddress(ctx context.Context, ownerAddress pe } // GetTokensIncrementallyByWalletAddress returns a list of tokens for an address -func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ownerAddress persist.Address) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { - recCh := make(chan multichain.ChainAgnosticTokensAndContracts, poolSize) +func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ownerAddress persist.Address) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + recCh := make(chan common.ChainAgnosticTokensAndContracts, poolSize) errCh := make(chan error) outCh := make(chan assetsReceived, 32) go func() { @@ -138,8 +138,8 @@ func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ow } // GetTokensIncrementallyByWalletAddress returns a list of tokens for a contract address -func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, address persist.Address, maxLimit int) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { - recCh := make(chan multichain.ChainAgnosticTokensAndContracts, poolSize) +func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, address persist.Address, maxLimit int) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + recCh := make(chan common.ChainAgnosticTokensAndContracts, poolSize) errCh := make(chan error) assetsCh := make(chan assetsReceived) go func() { @@ -155,7 +155,7 @@ func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, } // GetTokensByContractAddress returns a list of tokens for a contract address -func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, limit, offset int) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, limit, offset int) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { outCh := make(chan assetsReceived) go func() { defer close(outCh) @@ -163,9 +163,9 @@ func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddre }() tokens, contracts, err := p.assetsToTokens(ctx, "", outCh) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } - var contract multichain.ChainAgnosticContract + var contract common.ChainAgnosticContract if len(contracts) > 0 { contract = contracts[0] } @@ -173,7 +173,7 @@ func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddre } // GetTokensByTokenIdentifiers returns a list of tokens for a list of token identifiers -func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { outCh := make(chan assetsReceived) go func() { defer close(outCh) @@ -181,16 +181,16 @@ func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, ti multichai }() tokens, contracts, err := p.assetsToTokens(ctx, "", outCh) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } - contract := multichain.ChainAgnosticContract{} + contract := common.ChainAgnosticContract{} if len(contracts) > 0 { contract = contracts[0] } return tokens, contract, nil } -func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, ti multichain.ChainAgnosticIdentifiers, ownerAddress persist.Address) (multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, ti common.ChainAgnosticIdentifiers, ownerAddress persist.Address) (common.ChainAgnosticToken, common.ChainAgnosticContract, error) { outCh := make(chan assetsReceived) go func() { defer close(outCh) @@ -199,10 +199,10 @@ func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, ti mu tokens, contracts, err := p.assetsToTokens(ctx, ownerAddress, outCh) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } - contract := multichain.ChainAgnosticContract{} + contract := common.ChainAgnosticContract{} if len(contracts) > 0 { contract = contracts[0] } @@ -210,11 +210,11 @@ func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, ti mu if len(tokens) > 0 { return tokens[0], contract, nil } - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, fmt.Errorf("no tokens found for %s", ti) + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, fmt.Errorf("no tokens found for %s", ti) } // GetTokenMetadataByTokenIdentifiers retrieves a token's metadata for a given contract address and token ID -func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { +func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { tokens, _, err := p.GetTokensByTokenIdentifiers(ctx, ti) if err != nil { return nil, err @@ -227,30 +227,30 @@ func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti mu return tokens[0].TokenMetadata, nil } -func (p *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (multichain.ChainAgnosticTokenDescriptors, multichain.ChainAgnosticContractDescriptors, error) { +func (p *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) (common.ChainAgnosticTokenDescriptors, common.ChainAgnosticContractDescriptors, error) { tokens, contract, err := p.GetTokensByTokenIdentifiers(ctx, ti) if err != nil { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, err + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, err } if len(tokens) == 0 { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, fmt.Errorf("no tokens found for %s", ti) + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, fmt.Errorf("no tokens found for %s", ti) } return tokens[0].Descriptors, contract.Descriptors, nil } // GetContractByAddress returns a contract for a contract address -func (p *Provider) GetContractByAddress(ctx context.Context, contractAddress persist.Address) (multichain.ChainAgnosticContract, error) { +func (p *Provider) GetContractByAddress(ctx context.Context, contractAddress persist.Address) (common.ChainAgnosticContract, error) { cc, err := fetchContractCollectionByAddress(ctx, p.r, p.Chain, contractAddress) if err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } return contractCollectionToChainAgnosticContract(cc), nil } -func (p *Provider) assetsToTokens(ctx context.Context, ownerAddress persist.Address, outCh <-chan assetsReceived) (tokens []multichain.ChainAgnosticToken, contracts []multichain.ChainAgnosticContract, err error) { - recCh := make(chan multichain.ChainAgnosticTokensAndContracts, poolSize) +func (p *Provider) assetsToTokens(ctx context.Context, ownerAddress persist.Address, outCh <-chan assetsReceived) (tokens []common.ChainAgnosticToken, contracts []common.ChainAgnosticContract, err error) { + recCh := make(chan common.ChainAgnosticTokensAndContracts, poolSize) errCh := make(chan error) go func() { defer close(recCh) @@ -274,7 +274,7 @@ func (p *Provider) streamAssetsToTokens( ctx context.Context, ownerAddress persist.Address, outCh <-chan assetsReceived, - recCh chan<- multichain.ChainAgnosticTokensAndContracts, + recCh chan<- common.ChainAgnosticTokensAndContracts, errCh chan<- error, ) { cachedContracts := &sync.Map{} // used to avoid duplicate contract fetches @@ -294,7 +294,7 @@ func (p *Provider) streamAssetsToTokens( continue } - var out multichain.ChainAgnosticTokensAndContracts + var out common.ChainAgnosticTokensAndContracts // fetch contracts addresses := make([]persist.Address, len(page.Assets)) @@ -326,7 +326,7 @@ func (p *Provider) streamAssetsToTokens( } out.Tokens = append(out.Tokens, tokens...) - out.Contracts = append(out.Contracts, contract.(multichain.ChainAgnosticContract)) + out.Contracts = append(out.Contracts, contract.(common.ChainAgnosticContract)) } recCh <- out @@ -376,7 +376,7 @@ func (p *Provider) getChainAgnosticContract(ctx context.Context, contractAddress return nil } -func (p *Provider) assetToChainAgnosticTokens(ownerAddress persist.Address, asset Asset) ([]multichain.ChainAgnosticToken, error) { +func (p *Provider) assetToChainAgnosticTokens(ownerAddress persist.Address, asset Asset) ([]common.ChainAgnosticToken, error) { typ, err := tokenTypeFromAsset(asset) if err != nil { return nil, err @@ -384,7 +384,7 @@ func (p *Provider) assetToChainAgnosticTokens(ownerAddress persist.Address, asse if ownerAddress != "" { token := assetToAgnosticToken(asset, typ, ownerAddress, 1) - return []multichain.ChainAgnosticToken{token}, nil + return []common.ChainAgnosticToken{token}, nil } // No input owner address provided. OS doesn't return the owner of the token a few endpoints @@ -393,11 +393,11 @@ func (p *Provider) assetToChainAgnosticTokens(ownerAddress persist.Address, asse if typ == persist.TokenTypeERC721 && len(asset.Owners) == 1 { token := assetToAgnosticToken(asset, typ, persist.Address(asset.Owners[0].Address), 1) - return []multichain.ChainAgnosticToken{token}, nil + return []common.ChainAgnosticToken{token}, nil } if typ == persist.TokenTypeERC1155 && len(asset.Owners) > 0 { - tokens := make([]multichain.ChainAgnosticToken, len(asset.Owners)) + tokens := make([]common.ChainAgnosticToken, len(asset.Owners)) for i, o := range asset.Owners { tokens[i] = assetToAgnosticToken(asset, typ, persist.Address(o.Address), o.Quantity) } @@ -405,7 +405,7 @@ func (p *Provider) assetToChainAgnosticTokens(ownerAddress persist.Address, asse } token := assetToAgnosticToken(asset, typ, "", 1) - return []multichain.ChainAgnosticToken{token}, nil + return []common.ChainAgnosticToken{token}, nil } func fetchContractCollectionByAddress(ctx context.Context, r *retry.Retryer, chain persist.Chain, contractAddress persist.Address) (contractCollection, error) { @@ -535,23 +535,23 @@ func tokenTypeFromAsset(asset Asset) (persist.TokenType, error) { } } -func contractCollectionToChainAgnosticContract(contractCollection contractCollection) multichain.ChainAgnosticContract { - desc := multichain.ChainAgnosticContractDescriptors{ +func contractCollectionToChainAgnosticContract(contractCollection contractCollection) common.ChainAgnosticContract { + desc := common.ChainAgnosticContractDescriptors{ Symbol: "", // OpenSea doesn't provide this, but it isn't exposed in the schema anyway Name: contractCollection.Contract.Name, OwnerAddress: persist.Address(contractCollection.Collection.Owner), } - return multichain.ChainAgnosticContract{ + return common.ChainAgnosticContract{ Address: contractCollection.Contract.Address, Descriptors: desc, IsSpam: util.ToPointer(contractNameIsSpam(contractCollection.Contract.Name)), } } -func assetToAgnosticToken(asset Asset, tokenType persist.TokenType, tokenOwner persist.Address, quantity int) multichain.ChainAgnosticToken { - return multichain.ChainAgnosticToken{ +func assetToAgnosticToken(asset Asset, tokenType persist.TokenType, tokenOwner persist.Address, quantity int) common.ChainAgnosticToken { + return common.ChainAgnosticToken{ TokenType: tokenType, - Descriptors: multichain.ChainAgnosticTokenDescriptors{Name: asset.Name, Description: asset.Description}, + Descriptors: common.ChainAgnosticTokenDescriptors{Name: asset.Name, Description: asset.Description}, TokenURI: persist.TokenURI(asset.MetadataURL), TokenID: persist.MustTokenID(asset.Identifier), OwnerAddress: tokenOwner, @@ -606,11 +606,9 @@ func wrapMissingContractErr(chain persist.Chain, err error) error { a := strings.TrimPrefix(errMsg, "Contract ") a = strings.TrimSuffix(a, " not found") a = strings.TrimSpace(a) - return multichain.ErrProviderContractNotFound{ - Chain: chain, - Contract: persist.Address(a), - Err: err, - } + return fmt.Errorf("%s not found: %s", persist.ContractIdentifiers{ + Chain: chain, + ContractAddress: persist.Address(a)}, err) } return err } diff --git a/service/multichain/poap/poap.go b/service/multichain/poap/poap.go index e63681b5d..05c2389de 100644 --- a/service/multichain/poap/poap.go +++ b/service/multichain/poap/poap.go @@ -8,7 +8,7 @@ import ( "net/http" "github.com/mikeydub/go-gallery/env" - "github.com/mikeydub/go-gallery/service/multichain" + "github.com/mikeydub/go-gallery/service/multichain/common" "github.com/mikeydub/go-gallery/service/persist" "github.com/mikeydub/go-gallery/util" ) @@ -113,7 +113,7 @@ func NewProvider(httpClient *http.Client) *Provider { } // GetTokensByWalletAddress retrieves tokens for a wallet address on the Poap Blockchain -func (d *Provider) GetTokensByWalletAddress(ctx context.Context, addr persist.Address) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (d *Provider) GetTokensByWalletAddress(ctx context.Context, addr persist.Address) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { // DOES NOT SUPPORT PAGINATION req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/actions/scan/%s", d.apiURL, addr.String()), nil) @@ -138,8 +138,8 @@ func (d *Provider) GetTokensByWalletAddress(ctx context.Context, addr persist.Ad return resultTokens, resultContracts, nil } -func (d *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, addr persist.Address) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { - rec := make(chan multichain.ChainAgnosticTokensAndContracts) +func (d *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, addr persist.Address) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + rec := make(chan common.ChainAgnosticTokensAndContracts) errChan := make(chan error) go func() { defer close(rec) @@ -148,7 +148,7 @@ func (d *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ad errChan <- err return } - rec <- multichain.ChainAgnosticTokensAndContracts{ + rec <- common.ChainAgnosticTokensAndContracts{ Tokens: tokens, Contracts: contracts, } @@ -157,41 +157,41 @@ func (d *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ad } // GetTokensByContractAddress retrieves tokens for a contract address on the Poap Blockchain -func (d *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, limit, offset int) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { - return nil, multichain.ChainAgnosticContract{}, fmt.Errorf("poap has no way to retrieve tokens by contract address") +func (d *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, limit, offset int) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { + return nil, common.ChainAgnosticContract{}, fmt.Errorf("poap has no way to retrieve tokens by contract address") } // GetTokensByTokenIdentifiers retrieves tokens for a token identifiers on the Poap Blockchain -func (d *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentifiers multichain.ChainAgnosticIdentifiers, limit, offset int) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (d *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentifiers common.ChainAgnosticIdentifiers, limit, offset int) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { tid := tokenIdentifiers.TokenID req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/token/0x%s", d.apiURL, tid), nil) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } req.Header.Set("X-API-KEY", d.apiKey) resp, err := d.httpClient.Do(req) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, multichain.ChainAgnosticContract{}, util.GetErrFromResp(resp) + return nil, common.ChainAgnosticContract{}, util.GetErrFromResp(resp) } var token poapToken if err := json.NewDecoder(resp.Body).Decode(&token); err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } - return []multichain.ChainAgnosticToken{d.poapToToken(token)}, d.poapToContract(token), nil + return []common.ChainAgnosticToken{d.poapToToken(token)}, d.poapToContract(token), nil } -func (d *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, tokenIdentifiers multichain.ChainAgnosticIdentifiers) (multichain.ChainAgnosticTokenDescriptors, multichain.ChainAgnosticContractDescriptors, error) { +func (d *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, tokenIdentifiers common.ChainAgnosticIdentifiers) (common.ChainAgnosticTokenDescriptors, common.ChainAgnosticContractDescriptors, error) { tokens, contract, err := d.GetTokensByTokenIdentifiers(ctx, tokenIdentifiers, 1, 0) if err != nil { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, err + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, err } if len(tokens) == 0 { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, fmt.Errorf("no token found") + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, fmt.Errorf("no token found") } firstToken := tokens[0] @@ -199,77 +199,77 @@ func (d *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, to } // GetTokenByTokenIdentifiersAndOwner retrieves tokens for a token identifiers and owner address -func (d *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, tokenIdentifiers multichain.ChainAgnosticIdentifiers, ownerAddress persist.Address) (multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (d *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, tokenIdentifiers common.ChainAgnosticIdentifiers, ownerAddress persist.Address) (common.ChainAgnosticToken, common.ChainAgnosticContract, error) { tid := tokenIdentifiers.TokenID req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/token/0x%s", d.apiURL, tid), nil) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } req.Header.Set("X-API-KEY", d.apiKey) resp, err := d.httpClient.Do(req) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, util.GetErrFromResp(resp) + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, util.GetErrFromResp(resp) } var token poapToken if err := json.NewDecoder(resp.Body).Decode(&token); err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } return d.poapToToken(token), d.poapToContract(token), nil } -func (d *Provider) GetOwnedTokensByContract(ctx context.Context, contract persist.Address, addr persist.Address, limit, offset int) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (d *Provider) GetOwnedTokensByContract(ctx context.Context, contract persist.Address, addr persist.Address, limit, offset int) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/actions/scan/%s/%s", d.apiURL, addr.String(), contract), nil) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } req.Header.Set("X-API-KEY", d.apiKey) resp, err := d.httpClient.Do(req) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } var token poapToken if err := json.NewDecoder(resp.Body).Decode(&token); err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } resultToken := d.poapToToken(token) resultContract := d.poapToContract(token) - return []multichain.ChainAgnosticToken{resultToken}, resultContract, nil + return []common.ChainAgnosticToken{resultToken}, resultContract, nil } // GetContractByAddress retrieves an Poap contract by address -func (d *Provider) GetContractByAddress(ctx context.Context, addr persist.Address) (multichain.ChainAgnosticContract, error) { +func (d *Provider) GetContractByAddress(ctx context.Context, addr persist.Address) (common.ChainAgnosticContract, error) { req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/events/%s", d.apiURL, addr), nil) if err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } req.Header.Set("X-API-KEY", d.apiKey) resp, err := d.httpClient.Do(req) if err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return multichain.ChainAgnosticContract{}, util.GetErrFromResp(resp) + return common.ChainAgnosticContract{}, util.GetErrFromResp(resp) } var event poapEvent if err := json.NewDecoder(resp.Body).Decode(&event); err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } return d.eventToContract(event), nil } -func (d *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { +func (d *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { t, _, err := d.GetTokensByTokenIdentifiers(ctx, ti, 1, 0) if err != nil { return persist.TokenMetadata{}, err @@ -282,21 +282,21 @@ func (d *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti mu } // we should assume when using this function that the array is all of the tokens un paginated and we will need to paginate it with the offset and limit -func (d *Provider) poapsToTokens(pPoap []poapToken) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract) { - tokens := make([]multichain.ChainAgnosticToken, 0, len(pPoap)) - contracts := make([]multichain.ChainAgnosticContract, 0, len(pPoap)) +func (d *Provider) poapsToTokens(pPoap []poapToken) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract) { + tokens := make([]common.ChainAgnosticToken, 0, len(pPoap)) + contracts := make([]common.ChainAgnosticContract, 0, len(pPoap)) for _, poap := range pPoap { tokens = append(tokens, d.poapToToken(poap)) contracts = append(contracts, d.poapToContract(poap)) } return tokens, contracts } -func (d *Provider) poapToToken(pPoap poapToken) multichain.ChainAgnosticToken { +func (d *Provider) poapToToken(pPoap poapToken) common.ChainAgnosticToken { - return multichain.ChainAgnosticToken{ + return common.ChainAgnosticToken{ OwnerAddress: persist.Address(pPoap.Owner), TokenID: persist.HexTokenID(pPoap.TokenID.toBase16()), - Descriptors: multichain.ChainAgnosticTokenDescriptors{ + Descriptors: common.ChainAgnosticTokenDescriptors{ Name: pPoap.Event.Name, Description: pPoap.Event.Description, }, @@ -326,20 +326,20 @@ func (d *Provider) poapToToken(pPoap poapToken) multichain.ChainAgnosticToken { } } -func (d *Provider) poapToContract(pPoap poapToken) multichain.ChainAgnosticContract { +func (d *Provider) poapToContract(pPoap poapToken) common.ChainAgnosticContract { - return multichain.ChainAgnosticContract{ + return common.ChainAgnosticContract{ Address: persist.Address(pPoap.Event.FancyID), - Descriptors: multichain.ChainAgnosticContractDescriptors{ + Descriptors: common.ChainAgnosticContractDescriptors{ Name: pPoap.Event.Name, }, } } -func (d *Provider) eventToContract(pEvent poapEvent) multichain.ChainAgnosticContract { - return multichain.ChainAgnosticContract{ +func (d *Provider) eventToContract(pEvent poapEvent) common.ChainAgnosticContract { + return common.ChainAgnosticContract{ Address: persist.Address(pEvent.FancyID), - Descriptors: multichain.ChainAgnosticContractDescriptors{ + Descriptors: common.ChainAgnosticContractDescriptors{ Name: pEvent.Name, }, } diff --git a/service/multichain/reservoir/reservoir.go b/service/multichain/reservoir/reservoir.go index 083558b17..d1a9de257 100644 --- a/service/multichain/reservoir/reservoir.go +++ b/service/multichain/reservoir/reservoir.go @@ -11,7 +11,7 @@ import ( "github.com/mikeydub/go-gallery/env" "github.com/mikeydub/go-gallery/platform" - "github.com/mikeydub/go-gallery/service/multichain" + "github.com/mikeydub/go-gallery/service/multichain/common" "github.com/mikeydub/go-gallery/service/persist" "github.com/mikeydub/go-gallery/util" "github.com/mikeydub/go-gallery/util/retry" @@ -128,7 +128,7 @@ type Provider struct { // reservoir doesn't keep data for parent contracts - only collections in the parent contract // e.g collection data is available for projects within Art Blocks, but not for the Art Blocks // contract itself. We use another fetcher to get that data. - cFetcher multichain.ContractFetcher + cFetcher common.ContractFetcher r *retry.Retryer } @@ -162,7 +162,7 @@ func NewProvider(ctx context.Context, httpClient *http.Client, chain persist.Cha }, cleanup } -func (p *Provider) GetTokensByWalletAddress(ctx context.Context, ownerAddress persist.Address) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByWalletAddress(ctx context.Context, ownerAddress persist.Address) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { outCh := make(chan pageResult) go func() { defer close(outCh) @@ -171,8 +171,8 @@ func (p *Provider) GetTokensByWalletAddress(ctx context.Context, ownerAddress pe return assetsToTokens(ctx, p.chain, p.cFetcher, ownerAddress, outCh) } -func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ownerAddress persist.Address) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { - recCh := make(chan multichain.ChainAgnosticTokensAndContracts) +func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ownerAddress persist.Address) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + recCh := make(chan common.ChainAgnosticTokensAndContracts) errCh := make(chan error) outCh := make(chan pageResult) go func() { @@ -187,7 +187,7 @@ func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ow return recCh, errCh } -func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, limit int, offset int) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, limit int, offset int) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { outCh := make(chan pageResult) go func() { defer close(outCh) @@ -196,19 +196,19 @@ func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddre tokens, contracts, err := assetsToTokens(ctx, p.chain, p.cFetcher, "", outCh) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } if len(contracts) == 0 { - return nil, multichain.ChainAgnosticContract{}, ErrCollectionNotFoundByAddress{Address: contractAddress} + return nil, common.ChainAgnosticContract{}, ErrCollectionNotFoundByAddress{Address: contractAddress} } return tokens, contracts[0], nil } // GetTokensIncrementallyByContractAddress returns tokens for a contract address -func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, address persist.Address, maxLimit int) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { - recCh := make(chan multichain.ChainAgnosticTokensAndContracts) +func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, address persist.Address, maxLimit int) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + recCh := make(chan common.ChainAgnosticTokensAndContracts) errCh := make(chan error) outCh := make(chan pageResult) go func() { @@ -223,7 +223,7 @@ func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, return recCh, errCh } -func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, ti multichain.ChainAgnosticIdentifiers, ownerAddress persist.Address) (multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, ti common.ChainAgnosticIdentifiers, ownerAddress persist.Address) (common.ChainAgnosticToken, common.ChainAgnosticContract, error) { outCh := make(chan pageResult) go func() { defer close(outCh) @@ -232,21 +232,21 @@ func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, ti mu tokens, contracts, err := assetsToTokens(ctx, p.chain, p.cFetcher, ownerAddress, outCh) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } if len(tokens) == 0 { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, ErrTokenNotFoundByIdentifiers{ContractAddress: ti.ContractAddress, TokenID: ti.TokenID, OwnerAddress: ownerAddress} + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, ErrTokenNotFoundByIdentifiers{ContractAddress: ti.ContractAddress, TokenID: ti.TokenID, OwnerAddress: ownerAddress} } if len(contracts) == 0 { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, ErrCollectionNotFoundByAddress{Address: ti.ContractAddress} + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, ErrCollectionNotFoundByAddress{Address: ti.ContractAddress} } return tokens[0], contracts[0], nil } -func (p *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (multichain.ChainAgnosticTokenDescriptors, multichain.ChainAgnosticContractDescriptors, error) { +func (p *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) (common.ChainAgnosticTokenDescriptors, common.ChainAgnosticContractDescriptors, error) { outCh := make(chan pageResult) go func() { defer close(outCh) @@ -256,21 +256,21 @@ func (p *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, ti // ownerAddress is omitted, but its not required in this context tokens, contracts, err := assetsToTokens(ctx, p.chain, p.cFetcher, "", outCh) if err != nil { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, err + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, err } if len(tokens) == 0 { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, ErrTokenNotFoundByIdentifiers{ContractAddress: ti.ContractAddress, TokenID: ti.TokenID} + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, ErrTokenNotFoundByIdentifiers{ContractAddress: ti.ContractAddress, TokenID: ti.TokenID} } if len(contracts) == 0 { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, ErrCollectionNotFoundByAddress{Address: ti.ContractAddress} + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, ErrCollectionNotFoundByAddress{Address: ti.ContractAddress} } return tokens[0].Descriptors, contracts[0].Descriptors, nil } -func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { +func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { outCh := make(chan pageResult) go func() { defer close(outCh) @@ -293,18 +293,18 @@ func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti mu return tokens[0].TokenMetadata, nil } -func (p Provider) GetContractByAddress(ctx context.Context, chain persist.Chain, contractAddress persist.Address) (multichain.ChainAgnosticContract, error) { +func (p Provider) GetContractByAddress(ctx context.Context, chain persist.Chain, contractAddress persist.Address) (common.ChainAgnosticContract, error) { c, err := p.fetchCollectionByAddress(ctx, contractAddress) if err != nil { - return multichain.ChainAgnosticContract{}, ErrCollectionNotFoundByAddress{Address: contractAddress} + return common.ChainAgnosticContract{}, ErrCollectionNotFoundByAddress{Address: contractAddress} } return collectionToAgnosticContract(ctx, chain, p.cFetcher, c, contractAddress) } // GetTokensByTokenIdentifiersBatch returns a slice tokens from a list of token identifiers // Data is returned in the same order as the input. If a token is not found, the zero-value is used instead. -func (p Provider) GetTokensByTokenIdentifiersBatch(ctx context.Context, tIDs []multichain.ChainAgnosticIdentifiers) ([]multichain.ChainAgnosticToken, []error) { - asTokens := util.MapWithoutError(tIDs, func(ti multichain.ChainAgnosticIdentifiers) persist.TokenIdentifiers { +func (p Provider) GetTokensByTokenIdentifiersBatch(ctx context.Context, tIDs []common.ChainAgnosticIdentifiers) ([]common.ChainAgnosticToken, []error) { + asTokens := util.MapWithoutError(tIDs, func(ti common.ChainAgnosticIdentifiers) persist.TokenIdentifiers { return persist.NewTokenIdentifiers(ti.ContractAddress, ti.TokenID, p.chain) }) @@ -314,7 +314,7 @@ func (p Provider) GetTokensByTokenIdentifiersBatch(ctx context.Context, tIDs []m p.streamAssetsForTokens(ctx, asTokens, outCh) }() - ret := make([]multichain.ChainAgnosticToken, len(tIDs)) + ret := make([]common.ChainAgnosticToken, len(tIDs)) errs := make([]error, len(tIDs)) tokens, _, err := assetsToTokens(ctx, p.chain, nil, "", outCh) @@ -326,7 +326,7 @@ func (p Provider) GetTokensByTokenIdentifiersBatch(ctx context.Context, tIDs []m return nil, errs } - lookup := make(map[persist.TokenIdentifiers]multichain.ChainAgnosticToken) + lookup := make(map[persist.TokenIdentifiers]common.ChainAgnosticToken) for _, t := range tokens { lookup[persist.TokenIdentifiers{ TokenID: t.TokenID, @@ -451,7 +451,7 @@ func (p *Provider) fetchCollectionByAddress(ctx context.Context, contractAddress return res.Collections[0], nil } -func (p *Provider) fetchBlockScoutMetadata(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { +func (p *Provider) fetchBlockScoutMetadata(ctx context.Context, ti common.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { u := fmt.Sprintf("https://base.blockscout.com/api/v2/tokens/%s/instances/%s", ti.ContractAddress, ti.TokenID.Base10String()) req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { @@ -493,10 +493,10 @@ func (p *Provider) fetchBlockScoutMetadata(ctx context.Context, ti multichain.Ch return res.Metadata, nil } -func assetsToTokens(ctx context.Context, chain persist.Chain, cFetcher multichain.ContractFetcher, ownerAddress persist.Address, outCh <-chan pageResult) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { - resultTokens := make([]multichain.ChainAgnosticToken, 0, len(outCh)) - resultContracts := make([]multichain.ChainAgnosticContract, 0, len(outCh)) - seenCollections := make(map[string]multichain.ChainAgnosticContract) +func assetsToTokens(ctx context.Context, chain persist.Chain, cFetcher common.ContractFetcher, ownerAddress persist.Address, outCh <-chan pageResult) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { + resultTokens := make([]common.ChainAgnosticToken, 0, len(outCh)) + resultContracts := make([]common.ChainAgnosticContract, 0, len(outCh)) + seenCollections := make(map[string]common.ChainAgnosticContract) for page := range outCh { if page.Err != nil { return nil, nil, page.Err @@ -520,8 +520,8 @@ func assetsToTokens(ctx context.Context, chain persist.Chain, cFetcher multichai return resultTokens, resultContracts, nil } -func streamAssetsToTokens(ctx context.Context, chain persist.Chain, cFetcher multichain.ContractFetcher, ownerAddress persist.Address, outCh <-chan pageResult, recCh chan<- multichain.ChainAgnosticTokensAndContracts, errCh chan<- error) { - seenCollections := make(map[string]multichain.ChainAgnosticContract) +func streamAssetsToTokens(ctx context.Context, chain persist.Chain, cFetcher common.ContractFetcher, ownerAddress persist.Address, outCh <-chan pageResult, recCh chan<- common.ChainAgnosticTokensAndContracts, errCh chan<- error) { + seenCollections := make(map[string]common.ChainAgnosticContract) for page := range outCh { if page.Err != nil { @@ -529,8 +529,8 @@ func streamAssetsToTokens(ctx context.Context, chain persist.Chain, cFetcher mul return } - resultTokens := make([]multichain.ChainAgnosticToken, 0, len(page.Tokens)) - resultContracts := make([]multichain.ChainAgnosticContract, 0, len(page.Tokens)) + resultTokens := make([]common.ChainAgnosticToken, 0, len(page.Tokens)) + resultContracts := make([]common.ChainAgnosticContract, 0, len(page.Tokens)) for _, t := range page.Tokens { resultTokens = append(resultTokens, assetToAgnosticToken(t, ownerAddress)) @@ -549,14 +549,14 @@ func streamAssetsToTokens(ctx context.Context, chain persist.Chain, cFetcher mul resultContracts = append(resultContracts, seenCollections[collectionID]) } - recCh <- multichain.ChainAgnosticTokensAndContracts{ + recCh <- common.ChainAgnosticTokensAndContracts{ Tokens: resultTokens, Contracts: resultContracts, } } } -func assetToAgnosticToken(t TokenWithOwnership, ownerAddress persist.Address) multichain.ChainAgnosticToken { +func assetToAgnosticToken(t TokenWithOwnership, ownerAddress persist.Address) common.ChainAgnosticToken { var tokenType persist.TokenType switch t.Token.Kind { @@ -581,7 +581,7 @@ func assetToAgnosticToken(t TokenWithOwnership, ownerAddress persist.Address) mu tokenQuantity = persist.HexString(b.Text(16)) } - descriptors := multichain.ChainAgnosticTokenDescriptors{ + descriptors := common.ChainAgnosticTokenDescriptors{ Name: t.Token.Name, Description: t.Token.Description, } @@ -590,7 +590,7 @@ func assetToAgnosticToken(t TokenWithOwnership, ownerAddress persist.Address) mu ownerAddress = t.Token.Owner } - return multichain.ChainAgnosticToken{ + return common.ChainAgnosticToken{ ContractAddress: t.Token.Contract, Descriptors: descriptors, TokenType: tokenType, @@ -603,7 +603,7 @@ func assetToAgnosticToken(t TokenWithOwnership, ownerAddress persist.Address) mu } } -func collectionToAgnosticContract(ctx context.Context, chain persist.Chain, cFetcher multichain.ContractFetcher, c Collection, contractAddress persist.Address) (multichain.ChainAgnosticContract, error) { +func collectionToAgnosticContract(ctx context.Context, chain persist.Chain, cFetcher common.ContractFetcher, c Collection, contractAddress persist.Address) (common.ChainAgnosticContract, error) { // reservoir doesn't keep parent contract data if cFetcher != nil { if isSharedContract(c.ID) { @@ -614,9 +614,9 @@ func collectionToAgnosticContract(ctx context.Context, chain persist.Chain, cFet return cFetcher.GetContractByAddress(ctx, contractAddress) } } - return multichain.ChainAgnosticContract{ + return common.ChainAgnosticContract{ Address: contractAddress, - Descriptors: multichain.ChainAgnosticContractDescriptors{ + Descriptors: common.ChainAgnosticContractDescriptors{ Symbol: c.Symbol, Name: c.Name, Description: c.Description, diff --git a/service/multichain/simplehash/simplehash.go b/service/multichain/simplehash/simplehash.go index 1233f01be..c75fdbcb5 100644 --- a/service/multichain/simplehash/simplehash.go +++ b/service/multichain/simplehash/simplehash.go @@ -13,7 +13,7 @@ import ( "github.com/mikeydub/go-gallery/env" "github.com/mikeydub/go-gallery/service/logger" - mc "github.com/mikeydub/go-gallery/service/multichain" + "github.com/mikeydub/go-gallery/service/multichain/common" "github.com/mikeydub/go-gallery/service/persist" "github.com/mikeydub/go-gallery/util" "github.com/mikeydub/go-gallery/util/retry" @@ -163,7 +163,7 @@ func setSpamFilter(u url.URL, threshold int) url.URL { return u } -func setNftIDs(u url.URL, chain persist.Chain, ids []mc.ChainAgnosticIdentifiers) url.URL { +func setNftIDs(u url.URL, chain persist.Chain, ids []common.ChainAgnosticIdentifiers) url.URL { query := u.Query() nftIDs := make([]string, len(ids)) for i, id := range ids { @@ -314,7 +314,7 @@ type getOwnersByContractResponse struct { Owners []simplehashTokenOwner `json:"owners"` } -func translateToChainAgnosticToken(t simplehashNFT, ownerAddress persist.Address, isSpam *bool) mc.ChainAgnosticToken { +func translateToChainAgnosticToken(t simplehashNFT, ownerAddress persist.Address, isSpam *bool) common.ChainAgnosticToken { var tokenType persist.TokenType switch t.Contract.Type { @@ -323,7 +323,7 @@ func translateToChainAgnosticToken(t simplehashNFT, ownerAddress persist.Address case "ERC1155", "FA2": tokenType = persist.TokenTypeERC1155 default: - tID := mc.ChainAgnosticIdentifiers{ContractAddress: persist.Address(t.ContractAddress), TokenID: persist.HexTokenID(t.TokenID)} + tID := common.ChainAgnosticIdentifiers{ContractAddress: persist.Address(t.ContractAddress), TokenID: persist.HexTokenID(t.TokenID)} logger.For(context.Background()).Warnf("%s has unknown token type: %s", tID, t.Contract.Type) } @@ -340,8 +340,8 @@ func translateToChainAgnosticToken(t simplehashNFT, ownerAddress persist.Address quantity = persist.MustHexString(t.Owners[0].QuantityString) } - return mc.ChainAgnosticToken{ - Descriptors: mc.ChainAgnosticTokenDescriptors{ + return common.ChainAgnosticToken{ + Descriptors: common.ChainAgnosticTokenDescriptors{ Name: t.Name, Description: t.Description, }, @@ -370,9 +370,9 @@ func translateToChainAgnosticToken(t simplehashNFT, ownerAddress persist.Address } } -func translateToChainAgnosticContract(address string, contract simplehashContract, collection simplehashCollection) mc.ChainAgnosticContract { - c := mc.ChainAgnosticContract{ - Descriptors: mc.ChainAgnosticContractDescriptors{ +func translateToChainAgnosticContract(address string, contract simplehashContract, collection simplehashCollection) common.ChainAgnosticContract { + c := common.ChainAgnosticContract{ + Descriptors: common.ChainAgnosticContractDescriptors{ Symbol: contract.Symbol, Name: contract.Name, OwnerAddress: persist.Address(util.FirstNonEmptyString(contract.OwnedBy, contract.DeployedBy)), @@ -417,7 +417,7 @@ func readResponseBodyInto(ctx context.Context, httpClient *http.Client, url stri return util.UnmarshallBody(into, resp.Body) } -func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, tIDs mc.ChainAgnosticIdentifiers, owner persist.Address) (mc.ChainAgnosticToken, mc.ChainAgnosticContract, error) { +func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, tIDs common.ChainAgnosticIdentifiers, owner persist.Address) (common.ChainAgnosticToken, common.ChainAgnosticContract, error) { u := setChain(getNftsByWalletEndpoint, p.chain) u = setWallet(u, owner) u = setContractAddress(u, p.chain, tIDs.ContractAddress) @@ -432,7 +432,7 @@ outer: err := readResponseBodyInto(ctx, p.httpClient, next, &body) if err != nil { - return mc.ChainAgnosticToken{}, mc.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } for _, nft := range body.NFTs { @@ -453,7 +453,7 @@ outer: OwnerAddress: owner, }) logger.For(ctx).Error(err) - return mc.ChainAgnosticToken{}, mc.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } aContract := translateToChainAgnosticContract(token.ContractAddress, token.Contract, token.Collection) @@ -529,10 +529,10 @@ func (p *Provider) binRequestsByContract(ctx context.Context, address persist.Ad return outCh, errCh } -func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, address persist.Address) (<-chan mc.ChainAgnosticTokensAndContracts, <-chan error) { +func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, address persist.Address) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { batchRequestCh, batchRequestErrCh := p.binRequestsByContract(ctx, address) - outCh := make(chan mc.ChainAgnosticTokensAndContracts) + outCh := make(chan common.ChainAgnosticTokensAndContracts) errCh := make(chan error) go func() { @@ -574,7 +574,7 @@ func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ad return } - var page mc.ChainAgnosticTokensAndContracts + var page common.ChainAgnosticTokensAndContracts for _, nft := range body.NFTs { contract := translateToChainAgnosticContract(nft.ContractAddress, nft.Contract, nft.Collection) @@ -681,8 +681,8 @@ func (p *Provider) binRequestsByOwner(ctx context.Context, address persist.Addre return outCh, errCh } -func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, address persist.Address, maxLimit int) (<-chan mc.ChainAgnosticTokensAndContracts, <-chan error) { - outCh := make(chan mc.ChainAgnosticTokensAndContracts) +func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, address persist.Address, maxLimit int) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + outCh := make(chan common.ChainAgnosticTokensAndContracts) errCh := make(chan error) // Sample a token to get the token type @@ -691,7 +691,7 @@ func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, u = setCount(u) var sample getNftsByContractResponse - var sampleToken mc.ChainAgnosticToken + var sampleToken common.ChainAgnosticToken err := readResponseBodyInto(ctx, p.httpClient, u.String(), &sample) if err != nil { @@ -725,7 +725,7 @@ func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, errCh <- err } - var page mc.ChainAgnosticTokensAndContracts + var page common.ChainAgnosticTokensAndContracts for i := 0; i < len(body.NFTs) && total < maxLimit; i, total = i+1, total+1 { nft := body.NFTs[i] @@ -786,7 +786,7 @@ func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, return } - var page mc.ChainAgnosticTokensAndContracts + var page common.ChainAgnosticTokensAndContracts for i := 0; i < len(body.NFTs) && total.Load() < uint64(maxLimit); i, _ = i+1, total.Add(uint64(1)) { nft := body.NFTs[i] @@ -809,14 +809,14 @@ func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, return outCh, errCh } -func (p *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, tIDs []mc.ChainAgnosticIdentifiers) ([]persist.TokenMetadata, error) { +func (p *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, tIDs []common.ChainAgnosticIdentifiers) ([]persist.TokenMetadata, error) { if len(tIDs) == 0 { return []persist.TokenMetadata{}, nil } chunks := util.ChunkBy(tIDs, tokenBatchLimit) metadata := make([]persist.TokenMetadata, len(tIDs)) - lookup := make(map[mc.ChainAgnosticIdentifiers]persist.TokenMetadata) + lookup := make(map[common.ChainAgnosticIdentifiers]persist.TokenMetadata) for i, c := range chunks { batchID := i + 1 @@ -834,7 +834,7 @@ func (p *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, for _, t := range body.NFTs { token := translateToChainAgnosticToken(t, "", nil) - tID := mc.ChainAgnosticIdentifiers{ContractAddress: persist.Address(p.chain.NormalizeAddress(token.ContractAddress)), TokenID: token.TokenID} + tID := common.ChainAgnosticIdentifiers{ContractAddress: persist.Address(p.chain.NormalizeAddress(token.ContractAddress)), TokenID: token.TokenID} lookup[tID] = token.TokenMetadata } } @@ -846,14 +846,14 @@ func (p *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, return metadata, nil } -func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tID mc.ChainAgnosticIdentifiers) ([]mc.ChainAgnosticToken, mc.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tID common.ChainAgnosticIdentifiers) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { u := checkURL(fmt.Sprintf(getNftByTokenIDEndpointTemplate, baseURL, chainToSimpleHashChain[p.chain], tID.ContractAddress, tID.TokenID.ToDecimalTokenID())) var body simplehashNFT err := readResponseBodyInto(ctx, p.httpClient, u.String(), &body) if err != nil { - return nil, mc.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } if body.NftID == "" { @@ -863,15 +863,15 @@ func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tID mc.Chain TokenID: tID.TokenID, }) logger.For(ctx).Error(err) - return nil, mc.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } contract := translateToChainAgnosticContract(body.ContractAddress, body.Contract, body.Collection) token := translateToChainAgnosticToken(body, "", contract.IsSpam) - return []mc.ChainAgnosticToken{token}, contract, nil + return []common.ChainAgnosticToken{token}, contract, nil } -func (p *Provider) GetTokensByContractWallet(ctx context.Context, contract persist.ChainAddress, wallet persist.Address) ([]mc.ChainAgnosticToken, mc.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByContractWallet(ctx context.Context, contract persist.ChainAddress, wallet persist.Address) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { u := setChain(getNftsByWalletEndpoint, contract.Chain()) u = setContractAddress(u, contract.Chain(), contract.Address()) u = setWallet(u, wallet) @@ -879,15 +879,15 @@ func (p *Provider) GetTokensByContractWallet(ctx context.Context, contract persi next := u.String() - var t []mc.ChainAgnosticToken - var c mc.ChainAgnosticContract + var t []common.ChainAgnosticToken + var c common.ChainAgnosticContract for next != "" { var body getNftsByWalletResponse err := readResponseBodyInto(ctx, p.httpClient, next, &body) if err != nil { - return nil, mc.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } for _, nft := range body.NFTs { @@ -901,33 +901,33 @@ func (p *Provider) GetTokensByContractWallet(ctx context.Context, contract persi return t, c, nil } -func (p *Provider) GetContractByAddress(ctx context.Context, address persist.Address) (mc.ChainAgnosticContract, error) { +func (p *Provider) GetContractByAddress(ctx context.Context, address persist.Address) (common.ChainAgnosticContract, error) { // Needs at least one mint in order to fetch the contract, because the contract object is only available in the token response outCh, errCh := p.GetTokensIncrementallyByContractAddress(ctx, address, 1) for { select { case page := <-outCh: if len(page.Contracts) == 0 { - return mc.ChainAgnosticContract{}, fmt.Errorf("%s not found", persist.NewContractIdentifiers(address, p.chain)) + return common.ChainAgnosticContract{}, fmt.Errorf("%s not found", persist.NewContractIdentifiers(address, p.chain)) } return page.Contracts[0], nil case err := <-errCh: if err != nil { - return mc.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } } } } -func (p *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, tID mc.ChainAgnosticIdentifiers) (mc.ChainAgnosticTokenDescriptors, mc.ChainAgnosticContractDescriptors, error) { +func (p *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, tID common.ChainAgnosticIdentifiers) (common.ChainAgnosticTokenDescriptors, common.ChainAgnosticContractDescriptors, error) { tokens, contract, err := p.GetTokensByTokenIdentifiers(ctx, tID) if err != nil { - return mc.ChainAgnosticTokenDescriptors{}, mc.ChainAgnosticContractDescriptors{}, err + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, err } return tokens[0].Descriptors, contract.Descriptors, nil } -func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, tID mc.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { +func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, tID common.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { tokens, _, err := p.GetTokensByTokenIdentifiers(ctx, tID) if err != nil { return persist.TokenMetadata{}, err @@ -935,8 +935,8 @@ func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, tID m return tokens[0].TokenMetadata, nil } -func (p *Provider) GetContractsByCreatorAddress(ctx context.Context, address persist.Address) ([]mc.ChainAgnosticContract, error) { - contracts := make([]mc.ChainAgnosticContract, 0) +func (p *Provider) GetContractsByCreatorAddress(ctx context.Context, address persist.Address) ([]common.ChainAgnosticContract, error) { + contracts := make([]common.ChainAgnosticContract, 0) seen := make(map[persist.Address]bool) owned, err := p.GetContractsByOwnerAddress(ctx, address) @@ -964,8 +964,8 @@ func (p *Provider) GetContractsByCreatorAddress(ctx context.Context, address per return contracts, nil } -func (p *Provider) GetContractsByOwnerAddress(ctx context.Context, address persist.Address) ([]mc.ChainAgnosticContract, error) { - contracts := make([]mc.ChainAgnosticContract, 0) +func (p *Provider) GetContractsByOwnerAddress(ctx context.Context, address persist.Address) ([]common.ChainAgnosticContract, error) { + contracts := make([]common.ChainAgnosticContract, 0) u := setChain(getContractsByOwnerEndpoint, p.chain) u = setWallet(u, address) @@ -996,8 +996,8 @@ func (p *Provider) GetContractsByOwnerAddress(ctx context.Context, address persi return contracts, nil } -func (p *Provider) GetContractsByDeployerAddress(ctx context.Context, address persist.Address) ([]mc.ChainAgnosticContract, []bool, error) { - contracts := make([]mc.ChainAgnosticContract, 0) +func (p *Provider) GetContractsByDeployerAddress(ctx context.Context, address persist.Address) ([]common.ChainAgnosticContract, []bool, error) { + contracts := make([]common.ChainAgnosticContract, 0) hasOwner := make([]bool, 0) u := setChain(getContractsByDeployerEndpoint, p.chain) diff --git a/service/multichain/tzkt/tzkt.go b/service/multichain/tzkt/tzkt.go index bd39aa71b..26182fe69 100644 --- a/service/multichain/tzkt/tzkt.go +++ b/service/multichain/tzkt/tzkt.go @@ -13,7 +13,7 @@ import ( "github.com/mikeydub/go-gallery/env" "github.com/mikeydub/go-gallery/platform" "github.com/mikeydub/go-gallery/service/logger" - "github.com/mikeydub/go-gallery/service/multichain" + "github.com/mikeydub/go-gallery/service/multichain/common" "github.com/mikeydub/go-gallery/service/multichain/objkt" "github.com/mikeydub/go-gallery/service/multichain/tezos" "github.com/mikeydub/go-gallery/service/persist" @@ -95,7 +95,7 @@ func NewProvider(httpClient *http.Client) *Provider { } // GetTokensByWalletAddress retrieves tokens for a wallet address on the Tezos Blockchain -func (p *Provider) GetTokensByWalletAddress(ctx context.Context, addr persist.Address) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByWalletAddress(ctx context.Context, addr persist.Address) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { tzAddr, err := tezos.ToAddress(addr) if err != nil { return nil, nil, err @@ -124,8 +124,8 @@ func (p *Provider) GetTokensByWalletAddress(ctx context.Context, addr persist.Ad return p.tzBalanceTokensToTokens(ctx, resultTokens, addr.String()) } -func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, addr persist.Address) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { - rec := make(chan multichain.ChainAgnosticTokensAndContracts) +func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, addr persist.Address) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + rec := make(chan common.ChainAgnosticTokensAndContracts) errChan := make(chan error) go func() { defer close(rec) @@ -155,7 +155,7 @@ func (p *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ad logger.For(ctx).Debugf("converted %d tokens for address %s (limit %d offset %d)", len(resultTokens), tzAddr.String(), limit, offset) if len(resultTokens) > 0 || len(resultContracts) > 0 { - rec <- multichain.ChainAgnosticTokensAndContracts{ + rec <- common.ChainAgnosticTokensAndContracts{ Tokens: resultTokens, Contracts: resultContracts, } @@ -194,7 +194,7 @@ func (p *Provider) fetchBalancesByAddress(ctx context.Context, tzAddr persist.Ad } // GetTokensByContractAddress retrieves tokens for a contract address on the Tezos Blockchain -func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, maxLimit, startOffset int) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, maxLimit, startOffset int) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { offset := startOffset limit := int(math.Min(float64(maxLimit), float64(pageSize))) @@ -207,7 +207,7 @@ func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddre tzktBalances, err := p.fetchBalancesByContract(ctx, contractAddress, limit, offset) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } resultTokens = append(resultTokens, tzktBalances...) @@ -225,10 +225,10 @@ func (p *Provider) GetTokensByContractAddress(ctx context.Context, contractAddre tokens, contracts, err := p.tzBalanceTokensToTokens(ctx, resultTokens, contractAddress.String()) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } if len(contractAddress) == 0 { - return nil, multichain.ChainAgnosticContract{}, fmt.Errorf("no tez contract found for address: %s", contractAddress) + return nil, common.ChainAgnosticContract{}, fmt.Errorf("no tez contract found for address: %s", contractAddress) } contract := contracts[0] @@ -256,8 +256,8 @@ func (p *Provider) fetchBalancesByContract(ctx context.Context, contractAddress return tzktBalances, nil } -func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, addr persist.Address, maxLimit int) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { - rec := make(chan multichain.ChainAgnosticTokensAndContracts) +func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, addr persist.Address, maxLimit int) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + rec := make(chan common.ChainAgnosticTokensAndContracts) errChan := make(chan error) go func() { defer close(rec) @@ -290,7 +290,7 @@ func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, logger.For(ctx).Debugf("converted %d tokens for address %s (limit %d offset %d)", len(resultTokens), tzAddr.String(), limit, offset) if len(resultTokens) > 0 || len(resultContracts) > 0 { - rec <- multichain.ChainAgnosticTokensAndContracts{ + rec <- common.ChainAgnosticTokensAndContracts{ Tokens: resultTokens, Contracts: resultContracts, } @@ -314,7 +314,7 @@ func (p *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, } // GetTokensByTokenIdentifiers retrieves tokens for a token identifiers on the Tezos Blockchain -func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentifiers multichain.ChainAgnosticIdentifiers, maxLimit, startOffset int) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentifiers common.ChainAgnosticIdentifiers, maxLimit, startOffset int) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { offset := startOffset limit := int(math.Min(float64(maxLimit), float64(pageSize))) if limit < 1 { @@ -325,19 +325,19 @@ func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentif for { req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v1/tokens/balances?token.standard=fa2&token.tokenId=%s&token.contract=%s&limit=%d&offset=%d", p.apiURL, tokenIdentifiers.TokenID.Base10String(), tokenIdentifiers.ContractAddress, limit, offset), nil) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } resp, err := retry.RetryRequest(p.httpClient, req) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, multichain.ChainAgnosticContract{}, util.GetErrFromResp(resp) + return nil, common.ChainAgnosticContract{}, util.GetErrFromResp(resp) } var tzktBalances []tzktBalanceToken if err := json.NewDecoder(resp.Body).Decode(&tzktBalances); err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } resultTokens = append(resultTokens, tzktBalances...) @@ -356,10 +356,10 @@ func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentif tokens, contracts, err := p.tzBalanceTokensToTokens(ctx, resultTokens, tokenIdentifiers.String()) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } - contract := multichain.ChainAgnosticContract{} + contract := common.ChainAgnosticContract{} if len(contracts) > 0 { contract = contracts[0] } @@ -368,93 +368,93 @@ func (p *Provider) GetTokensByTokenIdentifiers(ctx context.Context, tokenIdentif } -func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, tokenIdentifiers multichain.ChainAgnosticIdentifiers, ownerAddress persist.Address) (multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, tokenIdentifiers common.ChainAgnosticIdentifiers, ownerAddress persist.Address) (common.ChainAgnosticToken, common.ChainAgnosticContract, error) { req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v1/tokens/balances?token.standard=fa2&token.tokenId=%s&token.contract=%s&account=%s&limit=1", p.apiURL, tokenIdentifiers.TokenID.Base10String(), tokenIdentifiers.ContractAddress, ownerAddress), nil) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } resp, err := retry.RetryRequest(p.httpClient, req) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, util.GetErrFromResp(resp) + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, util.GetErrFromResp(resp) } var tzktBalances []tzktBalanceToken if err := json.NewDecoder(resp.Body).Decode(&tzktBalances); err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } tokens, contracts, err := p.tzBalanceTokensToTokens(ctx, tzktBalances, tokenIdentifiers.String()) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } - contract := multichain.ChainAgnosticContract{} + contract := common.ChainAgnosticContract{} if len(contracts) > 0 { contract = contracts[0] } if len(tokens) > 0 { return tokens[0], contract, nil } else { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, fmt.Errorf("no token found for token identifiers: %s", tokenIdentifiers.String()) + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, fmt.Errorf("no token found for token identifiers: %s", tokenIdentifiers.String()) } } -func (p *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, tokenIdentifiers multichain.ChainAgnosticIdentifiers) (multichain.ChainAgnosticTokenDescriptors, multichain.ChainAgnosticContractDescriptors, error) { +func (p *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, tokenIdentifiers common.ChainAgnosticIdentifiers) (common.ChainAgnosticTokenDescriptors, common.ChainAgnosticContractDescriptors, error) { req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v1/tokens/balances?token.standard=fa2&token.tokenId=%s&token.contract=%s&limit=1", p.apiURL, tokenIdentifiers.TokenID.Base10String(), tokenIdentifiers.ContractAddress), nil) if err != nil { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, err + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, err } resp, err := retry.RetryRequest(p.httpClient, req) if err != nil { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, err + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, util.GetErrFromResp(resp) + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, util.GetErrFromResp(resp) } var tzktBalances []tzktBalanceToken if err := json.NewDecoder(resp.Body).Decode(&tzktBalances); err != nil { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, err + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, err } tokens, contracts, err := p.tzBalanceTokensToTokens(ctx, tzktBalances, tokenIdentifiers.String()) if err != nil { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, err + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, err } - contract := multichain.ChainAgnosticContract{} + contract := common.ChainAgnosticContract{} if len(contracts) > 0 { contract = contracts[0] } - token := multichain.ChainAgnosticToken{} + token := common.ChainAgnosticToken{} if len(tokens) > 0 { token = tokens[0] } else { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, fmt.Errorf("no token found for token identifiers: %s", tokenIdentifiers.String()) + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, fmt.Errorf("no token found for token identifiers: %s", tokenIdentifiers.String()) } return token.Descriptors, contract.Descriptors, nil } // GetContractByAddress retrieves an Tezos contract by address -func (p *Provider) GetContractByAddress(ctx context.Context, addr persist.Address) (multichain.ChainAgnosticContract, error) { +func (p *Provider) GetContractByAddress(ctx context.Context, addr persist.Address) (common.ChainAgnosticContract, error) { req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v1/contracts/%s?type=contract", p.apiURL, addr.String()), nil) if err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } resp, err := retry.RetryRequest(p.httpClient, req) if err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return multichain.ChainAgnosticContract{}, util.GetErrFromResp(resp) + return common.ChainAgnosticContract{}, util.GetErrFromResp(resp) } var tzktContract tzktContract if err := json.NewDecoder(resp.Body).Decode(&tzktContract); err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } return tzContractToContract(tzktContract), nil @@ -481,7 +481,7 @@ type tzktOrigination struct { } `json:"originatedContract"` } -func (p *Provider) GetContractsByCreatorAddress(ctx context.Context, addr persist.Address) ([]multichain.ChainAgnosticContract, error) { +func (p *Provider) GetContractsByCreatorAddress(ctx context.Context, addr persist.Address) ([]common.ChainAgnosticContract, error) { req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v1/operations/originations?sender=%s", p.apiURL, addr.String()), nil) if err != nil { return nil, err @@ -503,11 +503,11 @@ func (p *Provider) GetContractsByCreatorAddress(ctx context.Context, addr persis return o.OriginatedContract.Kind == "asset" && (util.ContainsString(o.OriginatedContract.Tzips, "fa2") || util.ContainsString(o.OriginatedContract.Tzips, "fa1.2")) }, false) - contracts := make([]multichain.ChainAgnosticContract, 0, len(filtered)) + contracts := make([]common.ChainAgnosticContract, 0, len(filtered)) for _, o := range filtered { - contracts = append(contracts, multichain.ChainAgnosticContract{ + contracts = append(contracts, common.ChainAgnosticContract{ Address: persist.Address(o.OriginatedContract.Address), - Descriptors: multichain.ChainAgnosticContractDescriptors{ + Descriptors: common.ChainAgnosticContractDescriptors{ Name: o.OriginatedContract.Alias, OwnerAddress: addr, }, @@ -517,7 +517,7 @@ func (p *Provider) GetContractsByCreatorAddress(ctx context.Context, addr persis return contracts, nil } -func (p *Provider) GetOwnedTokensByContract(ctx context.Context, contractAddress persist.Address, ownerAddress persist.Address, maxLimit, startOffset int) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (p *Provider) GetOwnedTokensByContract(ctx context.Context, contractAddress persist.Address, ownerAddress persist.Address, maxLimit, startOffset int) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { offset := 0 limit := int(math.Min(float64(maxLimit), float64(pageSize))) if limit < 1 { @@ -528,19 +528,19 @@ func (p *Provider) GetOwnedTokensByContract(ctx context.Context, contractAddress for { req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v1/tokens/balances?token.standard=fa2&account=%s&token.contract=%s&limit=%d&offset=%d", p.apiURL, ownerAddress, contractAddress, limit, offset), nil) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } resp, err := retry.RetryRequest(p.httpClient, req) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, multichain.ChainAgnosticContract{}, util.GetErrFromResp(resp) + return nil, common.ChainAgnosticContract{}, util.GetErrFromResp(resp) } var tzktBalances []tzktBalanceToken if err := json.NewDecoder(resp.Body).Decode(&tzktBalances); err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } resultTokens = append(resultTokens, tzktBalances...) @@ -559,16 +559,16 @@ func (p *Provider) GetOwnedTokensByContract(ctx context.Context, contractAddress tokens, contracts, err := p.tzBalanceTokensToTokens(ctx, resultTokens, fmt.Sprintf("%s:%s", contractAddress, ownerAddress)) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } - var contract multichain.ChainAgnosticContract + var contract common.ChainAgnosticContract if len(contracts) > 0 { contract = contracts[0] } return tokens, contract, nil } -func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { +func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { t, _, err := p.GetTokensByTokenIdentifiers(ctx, ti, 1, 0) if err != nil { return persist.TokenMetadata{}, err @@ -579,12 +579,12 @@ func (p *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti mu return t[0].TokenMetadata, nil } -func (p *Provider) tzBalanceTokensToTokens(pCtx context.Context, tzTokens []tzktBalanceToken, mediaKey string) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (p *Provider) tzBalanceTokensToTokens(pCtx context.Context, tzTokens []tzktBalanceToken, mediaKey string) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { tzTokens = dedupeBalances(tzTokens) seenContracts := map[string]bool{} contractsLock := &sync.Mutex{} - tokenChan := make(chan multichain.ChainAgnosticToken) - contractChan := make(chan multichain.ChainAgnosticContract) + tokenChan := make(chan common.ChainAgnosticToken) + contractChan := make(chan common.ChainAgnosticContract) errChan := make(chan error) ctx, cancel := context.WithCancel(pCtx) @@ -610,9 +610,9 @@ func (p *Provider) tzBalanceTokensToTokens(pCtx context.Context, tzTokens []tzkt return } - token := multichain.ChainAgnosticToken{ + token := common.ChainAgnosticToken{ TokenType: persist.TokenTypeERC1155, - Descriptors: multichain.ChainAgnosticTokenDescriptors{ + Descriptors: common.ChainAgnosticTokenDescriptors{ Description: tzToken.Token.Metadata.Description, Name: tzToken.Token.Metadata.Name, }, @@ -629,7 +629,7 @@ func (p *Provider) tzBalanceTokensToTokens(pCtx context.Context, tzTokens []tzkt // Try objkt if token isn't signed yet or has no metadata if !platform.IsFxhashSignedTezos(persist.ChainTezos, token.ContractAddress, token.Descriptors.Name) || !containsTezosKeywords(token.TokenMetadata) { - tIDs := multichain.ChainAgnosticIdentifiers{ContractAddress: tzToken.Token.Contract.Address, TokenID: persist.MustTokenID(tzToken.Token.TokenID)} + tIDs := common.ChainAgnosticIdentifiers{ContractAddress: tzToken.Token.Contract.Address, TokenID: persist.MustTokenID(tzToken.Token.TokenID)} objktTokens, objktContract, err := p.objktProvider.GetTokensByTokenIdentifiers(ctx, tIDs) if err == nil && len(objktTokens) > 0 { currentOwner := token.OwnerAddress @@ -667,8 +667,8 @@ func (p *Provider) tzBalanceTokensToTokens(pCtx context.Context, tzTokens []tzkt wp.StopWait() }() - resultTokens := make([]multichain.ChainAgnosticToken, 0, len(tzTokens)) - resultContracts := make([]multichain.ChainAgnosticContract, 0, len(tzTokens)) + resultTokens := make([]common.ChainAgnosticToken, 0, len(tzTokens)) + resultContracts := make([]common.ChainAgnosticContract, 0, len(tzTokens)) for { select { case <-ctx.Done(): @@ -692,7 +692,7 @@ func dedupeBalances(tzTokens []tzktBalanceToken) []tzktBalanceToken { seen := map[string]tzktBalanceToken{} result := make([]tzktBalanceToken, 0, len(tzTokens)) for _, t := range tzTokens { - id := multichain.ChainAgnosticIdentifiers{ContractAddress: t.Token.Contract.Address, TokenID: persist.HexTokenID(t.Token.TokenID)} + id := common.ChainAgnosticIdentifiers{ContractAddress: t.Token.Contract.Address, TokenID: persist.HexTokenID(t.Token.TokenID)} seen[id.String()] = t } for _, t := range seen { @@ -701,12 +701,12 @@ func dedupeBalances(tzTokens []tzktBalanceToken) []tzktBalanceToken { return result } -func tzContractToContract(tzContract tzktContract) multichain.ChainAgnosticContract { - return multichain.ChainAgnosticContract{ +func tzContractToContract(tzContract tzktContract) common.ChainAgnosticContract { + return common.ChainAgnosticContract{ Address: persist.Address(tzContract.Address), LatestBlock: persist.BlockNumber(tzContract.LastActivity), - Descriptors: multichain.ChainAgnosticContractDescriptors{ + Descriptors: common.ChainAgnosticContractDescriptors{ Name: tzContract.Alias, OwnerAddress: persist.Address(tzContract.Creator.Address), }, diff --git a/server/wire_gen.go b/service/multichain/wire_gen.go similarity index 85% rename from server/wire_gen.go rename to service/multichain/wire_gen.go index 916ee8fcc..a57bd3dca 100644 --- a/server/wire_gen.go +++ b/service/multichain/wire_gen.go @@ -4,7 +4,7 @@ //go:build !wireinject // +build !wireinject -package server +package multichain import ( "context" @@ -14,7 +14,7 @@ import ( "github.com/jackc/pgx/v4/pgxpool" "github.com/mikeydub/go-gallery/db/gen/coredb" "github.com/mikeydub/go-gallery/service/eth" - "github.com/mikeydub/go-gallery/service/multichain" + "github.com/mikeydub/go-gallery/service/multichain/custom" "github.com/mikeydub/go-gallery/service/multichain/poap" "github.com/mikeydub/go-gallery/service/multichain/simplehash" "github.com/mikeydub/go-gallery/service/multichain/tezos" @@ -33,22 +33,22 @@ import ( // Injectors from inject.go: // NewMultichainProvider is a wire injector that sets up a multichain provider instance -func NewMultichainProvider(ctx context.Context, envFunc func()) (*multichain.Provider, func()) { - serverEnvInit := setEnv(envFunc) - db, cleanup := newPqClient(serverEnvInit) - pool, cleanup2 := newPgxClient(serverEnvInit) +func NewMultichainProvider(ctx context.Context, envFunc func()) (*Provider, func()) { + multichainEnvInit := setEnv(envFunc) + db, cleanup := newPqClient(multichainEnvInit) + pool, cleanup2 := newPgxClient(multichainEnvInit) repositories := postgres.NewRepositories(db, pool) queries := newQueries(pool) client := _wireClientValue - ethereumProvider, cleanup3 := ethInjector(serverEnvInit, ctx, client) - tezosProvider := tezosInjector(serverEnvInit, client) + ethereumProvider, cleanup3 := ethInjector(multichainEnvInit, ctx, client) + tezosProvider := tezosInjector(multichainEnvInit, client) optimismProvider, cleanup4 := optimismInjector(ctx, client) arbitrumProvider, cleanup5 := arbitrumInjector(ctx, client) - poapProvider := poapInjector(serverEnvInit, client) - zoraProvider, cleanup6 := zoraInjector(serverEnvInit, ctx, client) + poapProvider := poapInjector(multichainEnvInit, client) + zoraProvider, cleanup6 := zoraInjector(multichainEnvInit, ctx, client) baseProvider, cleanup7 := baseInjector(ctx, client) polygonProvider, cleanup8 := polygonInjector(ctx, client) - chainProvider := &multichain.ChainProvider{ + chainProvider := &ChainProvider{ Ethereum: ethereumProvider, Tezos: tezosProvider, Optimism: optimismProvider, @@ -76,9 +76,9 @@ var ( _wireClientValue = http.DefaultClient ) -func multichainProviderInjector(ctx context.Context, repos *postgres.Repositories, q *coredb.Queries, chainProvider *multichain.ChainProvider, submitter *tokenmanage.TokenProcessingSubmitter) *multichain.Provider { +func multichainProviderInjector(ctx context.Context, repos *postgres.Repositories, q *coredb.Queries, chainProvider *ChainProvider, submitter *tokenmanage.TokenProcessingSubmitter) *Provider { providerLookup := newProviderLookup(chainProvider) - provider := &multichain.Provider{ + provider := &Provider{ Repos: repos, Queries: q, Chains: providerLookup, @@ -87,15 +87,15 @@ func multichainProviderInjector(ctx context.Context, repos *postgres.Repositorie return provider } -func customMetadataHandlersInjector() *multichain.CustomMetadataHandlers { +func customMetadataHandlersInjector() *custom.CustomMetadataHandlers { client := rpc.NewEthClient() shell := ipfs.NewShell() goarClient := arweave.NewClient() - customMetadataHandlers := multichain.NewCustomMetadataHandlers(client, shell, goarClient) + customMetadataHandlers := custom.NewCustomMetadataHandlers(client, shell, goarClient) return customMetadataHandlers } -func ethInjector(serverEnvInit envInit, contextContext context.Context, client *http.Client) (*multichain.EthereumProvider, func()) { +func ethInjector(multichainEnvInit envInit, contextContext context.Context, client *http.Client) (*EthereumProvider, func()) { chain := _wireChainValue provider := simplehash.NewProvider(chain, client) syncPipelineWrapper, cleanup := ethSyncPipelineInjector(contextContext, client, chain, provider) @@ -118,8 +118,8 @@ func ethVerifierInjector(ethClient *ethclient.Client) *eth.Verifier { return verifier } -func ethProviderInjector(ctx context.Context, syncPipeline *wrapper.SyncPipelineWrapper, verifier *eth.Verifier, simplehashProvider *simplehash.Provider) *multichain.EthereumProvider { - ethereumProvider := &multichain.EthereumProvider{ +func ethProviderInjector(ctx context.Context, syncPipeline *wrapper.SyncPipelineWrapper, verifier *eth.Verifier, simplehashProvider *simplehash.Provider) *EthereumProvider { + ethereumProvider := &EthereumProvider{ ContractFetcher: simplehashProvider, ContractsCreatorFetcher: simplehashProvider, TokenDescriptorsFetcher: simplehashProvider, @@ -151,7 +151,7 @@ func ethSyncPipelineInjector(ctx context.Context, httpClient *http.Client, chain } } -func tezosInjector(serverEnvInit envInit, client *http.Client) *multichain.TezosProvider { +func tezosInjector(multichainEnvInit envInit, client *http.Client) *TezosProvider { provider := tezos.NewProvider() chain := _wirePersistChainValue simplehashProvider := simplehash.NewProvider(chain, client) @@ -163,8 +163,8 @@ var ( _wirePersistChainValue = persist.ChainTezos ) -func tezosProviderInjector(tezosProvider *tezos.Provider, simplehashProvider *simplehash.Provider) *multichain.TezosProvider { - multichainTezosProvider := &multichain.TezosProvider{ +func tezosProviderInjector(tezosProvider *tezos.Provider, simplehashProvider *simplehash.Provider) *TezosProvider { + multichainTezosProvider := &TezosProvider{ ContractFetcher: simplehashProvider, ContractsCreatorFetcher: simplehashProvider, TokenDescriptorsFetcher: simplehashProvider, @@ -180,7 +180,7 @@ func tezosProviderInjector(tezosProvider *tezos.Provider, simplehashProvider *si return multichainTezosProvider } -func optimismInjector(contextContext context.Context, client *http.Client) (*multichain.OptimismProvider, func()) { +func optimismInjector(contextContext context.Context, client *http.Client) (*OptimismProvider, func()) { chain := _wireChainValue2 provider := simplehash.NewProvider(chain, client) syncPipelineWrapper, cleanup := optimismSyncPipelineInjector(contextContext, client, chain, provider) @@ -194,8 +194,8 @@ var ( _wireChainValue2 = persist.ChainOptimism ) -func optimismProviderInjector(syncPipeline *wrapper.SyncPipelineWrapper, simplehashProvider *simplehash.Provider) *multichain.OptimismProvider { - optimismProvider := &multichain.OptimismProvider{ +func optimismProviderInjector(syncPipeline *wrapper.SyncPipelineWrapper, simplehashProvider *simplehash.Provider) *OptimismProvider { + optimismProvider := &OptimismProvider{ ContractFetcher: simplehashProvider, ContractsCreatorFetcher: simplehashProvider, TokenDescriptorsFetcher: simplehashProvider, @@ -226,7 +226,7 @@ func optimismSyncPipelineInjector(ctx context.Context, httpClient *http.Client, } } -func arbitrumInjector(contextContext context.Context, client *http.Client) (*multichain.ArbitrumProvider, func()) { +func arbitrumInjector(contextContext context.Context, client *http.Client) (*ArbitrumProvider, func()) { chain := _wireChainValue3 provider := simplehash.NewProvider(chain, client) syncPipelineWrapper, cleanup := arbitrumSyncPipelineInjector(contextContext, client, chain, provider) @@ -240,8 +240,8 @@ var ( _wireChainValue3 = persist.ChainArbitrum ) -func arbitrumProviderInjector(syncPipeline *wrapper.SyncPipelineWrapper, simplehashProvider *simplehash.Provider) *multichain.ArbitrumProvider { - arbitrumProvider := &multichain.ArbitrumProvider{ +func arbitrumProviderInjector(syncPipeline *wrapper.SyncPipelineWrapper, simplehashProvider *simplehash.Provider) *ArbitrumProvider { + arbitrumProvider := &ArbitrumProvider{ ContractFetcher: simplehashProvider, ContractsCreatorFetcher: simplehashProvider, TokenDescriptorsFetcher: simplehashProvider, @@ -272,14 +272,14 @@ func arbitrumSyncPipelineInjector(ctx context.Context, httpClient *http.Client, } } -func poapInjector(serverEnvInit envInit, client *http.Client) *multichain.PoapProvider { +func poapInjector(multichainEnvInit envInit, client *http.Client) *PoapProvider { provider := poap.NewProvider(client) poapProvider := poapProviderInjector(provider) return poapProvider } -func poapProviderInjector(poapProvider *poap.Provider) *multichain.PoapProvider { - multichainPoapProvider := &multichain.PoapProvider{ +func poapProviderInjector(poapProvider *poap.Provider) *PoapProvider { + multichainPoapProvider := &PoapProvider{ TokenDescriptorsFetcher: poapProvider, TokenMetadataFetcher: poapProvider, TokensIncrementalOwnerFetcher: poapProvider, @@ -288,7 +288,7 @@ func poapProviderInjector(poapProvider *poap.Provider) *multichain.PoapProvider return multichainPoapProvider } -func zoraInjector(serverEnvInit envInit, contextContext context.Context, client *http.Client) (*multichain.ZoraProvider, func()) { +func zoraInjector(multichainEnvInit envInit, contextContext context.Context, client *http.Client) (*ZoraProvider, func()) { chain := _wireChainValue4 provider := simplehash.NewProvider(chain, client) syncPipelineWrapper, cleanup := zoraSyncPipelineInjector(contextContext, client, chain, provider) @@ -302,8 +302,8 @@ var ( _wireChainValue4 = persist.ChainZora ) -func zoraProviderInjector(syncPipeline *wrapper.SyncPipelineWrapper, simplehashProvider *simplehash.Provider) *multichain.ZoraProvider { - zoraProvider := &multichain.ZoraProvider{ +func zoraProviderInjector(syncPipeline *wrapper.SyncPipelineWrapper, simplehashProvider *simplehash.Provider) *ZoraProvider { + zoraProvider := &ZoraProvider{ ContractFetcher: simplehashProvider, ContractsCreatorFetcher: simplehashProvider, TokenDescriptorsFetcher: simplehashProvider, @@ -334,7 +334,7 @@ func zoraSyncPipelineInjector(ctx context.Context, httpClient *http.Client, chai } } -func baseInjector(contextContext context.Context, client *http.Client) (*multichain.BaseProvider, func()) { +func baseInjector(contextContext context.Context, client *http.Client) (*BaseProvider, func()) { chain := _wireChainValue5 provider := simplehash.NewProvider(chain, client) syncPipelineWrapper, cleanup := baseSyncPipelineInjector(contextContext, client, chain, provider) @@ -348,8 +348,8 @@ var ( _wireChainValue5 = persist.ChainBase ) -func baseProvidersInjector(syncPipeline *wrapper.SyncPipelineWrapper, simplehashProvider *simplehash.Provider) *multichain.BaseProvider { - baseProvider := &multichain.BaseProvider{ +func baseProvidersInjector(syncPipeline *wrapper.SyncPipelineWrapper, simplehashProvider *simplehash.Provider) *BaseProvider { + baseProvider := &BaseProvider{ ContractFetcher: simplehashProvider, ContractsCreatorFetcher: simplehashProvider, TokenDescriptorsFetcher: simplehashProvider, @@ -380,7 +380,7 @@ func baseSyncPipelineInjector(ctx context.Context, httpClient *http.Client, chai } } -func polygonInjector(contextContext context.Context, client *http.Client) (*multichain.PolygonProvider, func()) { +func polygonInjector(contextContext context.Context, client *http.Client) (*PolygonProvider, func()) { chain := _wireChainValue6 provider := simplehash.NewProvider(chain, client) syncPipelineWrapper, cleanup := polygonSyncPipelineInjector(contextContext, client, chain, provider) @@ -394,8 +394,8 @@ var ( _wireChainValue6 = persist.ChainPolygon ) -func polygonProvidersInjector(syncPipeline *wrapper.SyncPipelineWrapper, simplehashProvider *simplehash.Provider) *multichain.PolygonProvider { - polygonProvider := &multichain.PolygonProvider{ +func polygonProvidersInjector(syncPipeline *wrapper.SyncPipelineWrapper, simplehashProvider *simplehash.Provider) *PolygonProvider { + polygonProvider := &PolygonProvider{ ContractFetcher: simplehashProvider, ContractsCreatorFetcher: simplehashProvider, TokenDescriptorsFetcher: simplehashProvider, @@ -477,6 +477,6 @@ func newTokenManageCache() *redis.Cache { } // New chains must be added here -func newProviderLookup(p *multichain.ChainProvider) multichain.ProviderLookup { - return multichain.ProviderLookup{persist.ChainETH: p.Ethereum, persist.ChainTezos: p.Tezos, persist.ChainOptimism: p.Optimism, persist.ChainArbitrum: p.Arbitrum, persist.ChainPOAP: p.Poap, persist.ChainZora: p.Zora, persist.ChainBase: p.Base, persist.ChainPolygon: p.Polygon} +func newProviderLookup(p *ChainProvider) ProviderLookup { + return ProviderLookup{persist.ChainETH: p.Ethereum, persist.ChainTezos: p.Tezos, persist.ChainOptimism: p.Optimism, persist.ChainArbitrum: p.Arbitrum, persist.ChainPOAP: p.Poap, persist.ChainZora: p.Zora, persist.ChainBase: p.Base, persist.ChainPolygon: p.Polygon} } diff --git a/service/multichain/wrapper/wrapper.go b/service/multichain/wrapper/wrapper.go index 5b3a10d46..402b7a106 100644 --- a/service/multichain/wrapper/wrapper.go +++ b/service/multichain/wrapper/wrapper.go @@ -5,7 +5,8 @@ import ( "fmt" "github.com/mikeydub/go-gallery/service/logger" - "github.com/mikeydub/go-gallery/service/multichain" + "github.com/mikeydub/go-gallery/service/multichain/common" + "github.com/mikeydub/go-gallery/service/multichain/custom" "github.com/mikeydub/go-gallery/service/persist" sentryutil "github.com/mikeydub/go-gallery/service/sentry" ) @@ -15,58 +16,58 @@ import ( // fills missing token fields with data from a supplemental provider. type SyncPipelineWrapper struct { Chain persist.Chain - TokenIdentifierOwnerFetcher multichain.TokenIdentifierOwnerFetcher - TokensIncrementalOwnerFetcher multichain.TokensIncrementalOwnerFetcher - TokensIncrementalContractFetcher multichain.TokensIncrementalContractFetcher - TokenMetadataBatcher multichain.TokenMetadataBatcher - TokensByTokenIdentifiersFetcher multichain.TokensByTokenIdentifiersFetcher - TokensByContractWalletFetcher multichain.TokensByContractWalletFetcher - CustomMetadataWrapper *multichain.CustomMetadataHandlers + TokenIdentifierOwnerFetcher common.TokenIdentifierOwnerFetcher + TokensIncrementalOwnerFetcher common.TokensIncrementalOwnerFetcher + TokensIncrementalContractFetcher common.TokensIncrementalContractFetcher + TokenMetadataBatcher common.TokenMetadataBatcher + TokensByTokenIdentifiersFetcher common.TokensByTokenIdentifiersFetcher + TokensByContractWalletFetcher common.TokensByContractWalletFetcher + CustomMetadataWrapper *custom.CustomMetadataHandlers } -func (w SyncPipelineWrapper) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, ti multichain.ChainAgnosticIdentifiers, address persist.Address) (t multichain.ChainAgnosticToken, c multichain.ChainAgnosticContract, err error) { +func (w SyncPipelineWrapper) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, ti common.ChainAgnosticIdentifiers, address persist.Address) (t common.ChainAgnosticToken, c common.ChainAgnosticContract, err error) { t, c, err = w.TokenIdentifierOwnerFetcher.GetTokenByTokenIdentifiersAndOwner(ctx, ti, address) t = w.CustomMetadataWrapper.AddToToken(ctx, w.Chain, t) return t, c, err } -func (w SyncPipelineWrapper) GetTokensIncrementallyByWalletAddress(ctx context.Context, address persist.Address) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { +func (w SyncPipelineWrapper) GetTokensIncrementallyByWalletAddress(ctx context.Context, address persist.Address) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { recCh, errCh := w.TokensIncrementalOwnerFetcher.GetTokensIncrementallyByWalletAddress(ctx, address) recCh, errCh = w.CustomMetadataWrapper.AddToPage(ctx, w.Chain, recCh, errCh) return recCh, errCh } -func (w SyncPipelineWrapper) GetTokensIncrementallyByContractAddress(ctx context.Context, address persist.Address, maxLimit int) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { +func (w SyncPipelineWrapper) GetTokensIncrementallyByContractAddress(ctx context.Context, address persist.Address, maxLimit int) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { recCh, errCh := w.TokensIncrementalContractFetcher.GetTokensIncrementallyByContractAddress(ctx, address, maxLimit) recCh, errCh = w.CustomMetadataWrapper.AddToPage(ctx, w.Chain, recCh, errCh) return recCh, errCh } -func (w SyncPipelineWrapper) GetTokensByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (w SyncPipelineWrapper) GetTokensByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { t, c, err := w.TokensByTokenIdentifiersFetcher.GetTokensByTokenIdentifiers(ctx, ti) t = w.CustomMetadataWrapper.LoadAll(ctx, w.Chain, t) return t, c, err } -func (w SyncPipelineWrapper) GetTokensByContractWallet(ctx context.Context, address persist.ChainAddress, wallet persist.Address) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (w SyncPipelineWrapper) GetTokensByContractWallet(ctx context.Context, address persist.ChainAddress, wallet persist.Address) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { t, c, err := w.TokensByContractWalletFetcher.GetTokensByContractWallet(ctx, address, wallet) t = w.CustomMetadataWrapper.LoadAll(ctx, w.Chain, t) return t, c, err } -func (w SyncPipelineWrapper) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { - metadata, err := w.GetTokenMetadataByTokenIdentifiersBatch(ctx, []multichain.ChainAgnosticIdentifiers{ti}) +func (w SyncPipelineWrapper) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { + metadata, err := w.GetTokenMetadataByTokenIdentifiersBatch(ctx, []common.ChainAgnosticIdentifiers{ti}) return metadata[0], err } -func (w SyncPipelineWrapper) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, tIDs []multichain.ChainAgnosticIdentifiers) ([]persist.TokenMetadata, error) { +func (w SyncPipelineWrapper) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, tIDs []common.ChainAgnosticIdentifiers) ([]persist.TokenMetadata, error) { ret := make([]persist.TokenMetadata, len(tIDs)) - noCustomHandlerBatch := make([]multichain.ChainAgnosticIdentifiers, 0, len(tIDs)) + noCustomHandlerBatch := make([]common.ChainAgnosticIdentifiers, 0, len(tIDs)) noCustomHandlerResultIdxToInputIdx := make(map[int]int) // Separate tokens that have custom metadata handlers from those that don't for i, tID := range tIDs { - t := multichain.ChainAgnosticIdentifiers{ContractAddress: tID.ContractAddress, TokenID: tID.TokenID} + t := common.ChainAgnosticIdentifiers{ContractAddress: tID.ContractAddress, TokenID: tID.TokenID} metadata := w.CustomMetadataWrapper.Load(ctx, w.Chain, t) if len(metadata) > 0 { ret[i] = metadata diff --git a/service/multichain/zora/zora.go b/service/multichain/zora/zora.go index a252717d9..64791f1b3 100644 --- a/service/multichain/zora/zora.go +++ b/service/multichain/zora/zora.go @@ -14,7 +14,7 @@ import ( "github.com/mikeydub/go-gallery/env" "github.com/mikeydub/go-gallery/service/logger" "github.com/mikeydub/go-gallery/service/media" - "github.com/mikeydub/go-gallery/service/multichain" + "github.com/mikeydub/go-gallery/service/multichain/common" "github.com/mikeydub/go-gallery/service/persist" "github.com/mikeydub/go-gallery/util" ) @@ -149,13 +149,13 @@ type getTokensResponse struct { } // GetTokensByWalletAddress retrieves tokens for a wallet address on the zora Blockchain -func (d *Provider) GetTokensByWalletAddress(ctx context.Context, addr persist.Address) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (d *Provider) GetTokensByWalletAddress(ctx context.Context, addr persist.Address) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { url := fmt.Sprintf("%s/user/%s/tokens?chain_names=ZORA-MAINNET&sort_direction=DESC", zoraRESTURL, addr.String()) return d.getTokens(ctx, url, nil, true) } -func (d *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, addr persist.Address) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { - recCh := make(chan multichain.ChainAgnosticTokensAndContracts) +func (d *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, addr persist.Address) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + recCh := make(chan common.ChainAgnosticTokensAndContracts) errCh := make(chan error) url := fmt.Sprintf("%s/user/%s/tokens?chain_names=ZORA-MAINNET&sort_direction=DESC", zoraRESTURL, addr.String()) go func() { @@ -170,14 +170,14 @@ func (d *Provider) GetTokensIncrementallyByWalletAddress(ctx context.Context, ad return recCh, errCh } -func (d *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, ti multichain.ChainAgnosticIdentifiers, owner persist.Address) (multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (d *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, ti common.ChainAgnosticIdentifiers, owner persist.Address) (common.ChainAgnosticToken, common.ChainAgnosticContract, error) { tokens, contracts, err := d.GetTokensByWalletAddress(ctx, owner) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } - var resultToken multichain.ChainAgnosticToken - var resultContract multichain.ChainAgnosticContract + var resultToken common.ChainAgnosticToken + var resultContract common.ChainAgnosticContract for _, token := range tokens { if strings.EqualFold(token.ContractAddress.String(), ti.ContractAddress.String()) && strings.EqualFold(token.TokenID.String(), ti.TokenID.String()) { resultToken = token @@ -192,13 +192,13 @@ func (d *Provider) GetTokenByTokenIdentifiersAndOwner(ctx context.Context, ti mu } if resultToken.TokenID == "" || resultContract.Address == "" { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, fmt.Errorf("no token found for identifiers %+v", ti) + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, fmt.Errorf("no token found for identifiers %+v", ti) } return resultToken, resultContract, nil } -func (d *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { +func (d *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) (persist.TokenMetadata, error) { url := fmt.Sprintf("%s/contract/ZORA-MAINNET/%s?token_id=%s", zoraRESTURL, ti.ContractAddress.String(), ti.TokenID.Base10String()) token, _, err := d.getToken(ctx, "", url) if err != nil { @@ -210,33 +210,33 @@ func (d *Provider) GetTokenMetadataByTokenIdentifiers(ctx context.Context, ti mu return token.TokenMetadata, nil } -func (d *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) (multichain.ChainAgnosticTokenDescriptors, multichain.ChainAgnosticContractDescriptors, error) { +func (d *Provider) GetTokenDescriptorsByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) (common.ChainAgnosticTokenDescriptors, common.ChainAgnosticContractDescriptors, error) { url := fmt.Sprintf("%s/contract/ZORA-MAINNET/%s?token_id=%s", zoraRESTURL, ti.ContractAddress.String(), ti.TokenID.Base10String()) token, contract, err := d.getToken(ctx, "", url) if err != nil { - return multichain.ChainAgnosticTokenDescriptors{}, multichain.ChainAgnosticContractDescriptors{}, err + return common.ChainAgnosticTokenDescriptors{}, common.ChainAgnosticContractDescriptors{}, err } return token.Descriptors, contract.Descriptors, nil } // GetTokensByContractAddress retrieves tokens for a contract address on the zora Blockchain -func (d *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, limit, offset int) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (d *Provider) GetTokensByContractAddress(ctx context.Context, contractAddress persist.Address, limit, offset int) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { url := fmt.Sprintf("%s/tokens/ZORA-MAINNET/%s?&sort_key=CREATED&sort_direction=DESC", zoraRESTURL, contractAddress.String()) tokens, contracts, err := d.getTokens(ctx, url, nil, false) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } if len(contracts) == 0 { logger.For(ctx).Warnf("invalid number of contracts returned from zora: %d", len(contracts)) - return nil, multichain.ChainAgnosticContract{}, nil + return nil, common.ChainAgnosticContract{}, nil } return tokens, contracts[0], nil } -func (d *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, addr persist.Address, limit int) (<-chan multichain.ChainAgnosticTokensAndContracts, <-chan error) { - recCh := make(chan multichain.ChainAgnosticTokensAndContracts) +func (d *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, addr persist.Address, limit int) (<-chan common.ChainAgnosticTokensAndContracts, <-chan error) { + recCh := make(chan common.ChainAgnosticTokensAndContracts) errCh := make(chan error) url := fmt.Sprintf("%s/tokens/ZORA-MAINNET/%s?&sort_key=CREATED&sort_direction=DESC", zoraRESTURL, addr.String()) go func() { @@ -252,17 +252,17 @@ func (d *Provider) GetTokensIncrementallyByContractAddress(ctx context.Context, } // GetContractByAddress retrieves an zora contract by address -func (d *Provider) GetContractByAddress(ctx context.Context, addr persist.Address) (multichain.ChainAgnosticContract, error) { +func (d *Provider) GetContractByAddress(ctx context.Context, addr persist.Address) (common.ChainAgnosticContract, error) { url := fmt.Sprintf("%s/contract/ZORA-MAINNET/%s", zoraRESTURL, addr.String()) _, contract, err := d.getToken(ctx, "", url) if err != nil { - return multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticContract{}, err } return contract, nil } -func (d *Provider) GetContractsByCreatorAddress(ctx context.Context, addr persist.Address) ([]multichain.ChainAgnosticContract, error) { +func (d *Provider) GetContractsByCreatorAddress(ctx context.Context, addr persist.Address) ([]common.ChainAgnosticContract, error) { req := graphql.NewRequest(`query createdTokens($creator: Bytes!) { zoraCreateContracts(where: {creator: $creator}) { address @@ -286,10 +286,10 @@ func (d *Provider) GetContractsByCreatorAddress(ctx context.Context, addr persis logger.For(ctx).Infof("zora contracts retrieved: %d (%+v)", len(resp.ZoraCreateContracts), resp.ZoraCreateContracts) - result := make([]multichain.ChainAgnosticContract, len(resp.ZoraCreateContracts)) + result := make([]common.ChainAgnosticContract, len(resp.ZoraCreateContracts)) for i, contract := range resp.ZoraCreateContracts { - result[i] = multichain.ChainAgnosticContract{ - Descriptors: multichain.ChainAgnosticContractDescriptors{ + result[i] = common.ChainAgnosticContract{ + Descriptors: common.ChainAgnosticContractDescriptors{ Symbol: contract.Symbol, Name: contract.Name, OwnerAddress: addr, @@ -301,7 +301,7 @@ func (d *Provider) GetContractsByCreatorAddress(ctx context.Context, addr persis return result, nil } -func (d *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, tIDs []multichain.ChainAgnosticIdentifiers) ([]persist.TokenMetadata, error) { +func (d *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, tIDs []common.ChainAgnosticIdentifiers) ([]persist.TokenMetadata, error) { chunkSize := 50 chunks := util.ChunkBy(tIDs, chunkSize) metadatas := make([]persist.TokenMetadata, len(tIDs)) @@ -331,7 +331,7 @@ func (d *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, } // zora doesn't return tokens in the same order as the input - lookup := make(map[multichain.ChainAgnosticIdentifiers]persist.TokenMetadata) + lookup := make(map[common.ChainAgnosticIdentifiers]persist.TokenMetadata) for i, chunk := range chunks { batchID := i + 1 @@ -360,7 +360,7 @@ func (d *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, } for _, t := range batchResp.Tokens.Nodes { - tID := multichain.ChainAgnosticIdentifiers{ContractAddress: persist.Address(t.Token.CollectionAddress), TokenID: persist.MustTokenID(t.Token.TokenID)} + tID := common.ChainAgnosticIdentifiers{ContractAddress: persist.Address(t.Token.CollectionAddress), TokenID: persist.MustTokenID(t.Token.TokenID)} lookup[tID] = persist.TokenMetadata(t.Token.Metadata) } } @@ -373,22 +373,22 @@ func (d *Provider) GetTokenMetadataByTokenIdentifiersBatch(ctx context.Context, return metadatas, nil } -func (d *Provider) GetTokensByTokenIdentifiers(ctx context.Context, ti multichain.ChainAgnosticIdentifiers) ([]multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (d *Provider) GetTokensByTokenIdentifiers(ctx context.Context, ti common.ChainAgnosticIdentifiers) ([]common.ChainAgnosticToken, common.ChainAgnosticContract, error) { url := fmt.Sprintf("%s/contract/ZORA-MAINNET/%s?token_id=%s", zoraRESTURL, ti.ContractAddress.String(), ti.TokenID.Base10String()) token, contract, err := d.getToken(ctx, "", url) if err != nil { - return nil, multichain.ChainAgnosticContract{}, err + return nil, common.ChainAgnosticContract{}, err } - return []multichain.ChainAgnosticToken{token}, contract, nil + return []common.ChainAgnosticToken{token}, contract, nil } const maxLimit = 1000 -func (d *Provider) getTokens(ctx context.Context, url string, recCh chan<- multichain.ChainAgnosticTokensAndContracts, balance bool) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract, error) { +func (d *Provider) getTokens(ctx context.Context, url string, recCh chan<- common.ChainAgnosticTokensAndContracts, balance bool) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract, error) { offset := 0 limit := 50 - allTokens := []multichain.ChainAgnosticToken{} - allContracts := []multichain.ChainAgnosticContract{} + allTokens := []common.ChainAgnosticToken{} + allContracts := []common.ChainAgnosticContract{} for ; ; offset += limit { urlWithPagination := fmt.Sprintf("%s&offset=%d&limit=%d", url, offset, limit) logger.For(ctx).Infof("getting zora tokens from %s", urlWithPagination) @@ -402,8 +402,8 @@ func (d *Provider) getTokens(ctx context.Context, url string, recCh chan<- multi } defer resp.Body.Close() - var tokens []multichain.ChainAgnosticToken - var contracts []multichain.ChainAgnosticContract + var tokens []common.ChainAgnosticToken + var contracts []common.ChainAgnosticContract var willBreak bool if balance { var result getBalanceTokensResponse @@ -443,7 +443,7 @@ func (d *Provider) getTokens(ctx context.Context, url string, recCh chan<- multi } if recCh != nil { - recCh <- multichain.ChainAgnosticTokensAndContracts{ + recCh <- common.ChainAgnosticTokensAndContracts{ Tokens: tokens, Contracts: contracts, } @@ -459,27 +459,27 @@ func (d *Provider) getTokens(ctx context.Context, url string, recCh chan<- multi return allTokens, allContracts, nil } -func (d *Provider) getToken(ctx context.Context, ownerAddress persist.Address, url string) (multichain.ChainAgnosticToken, multichain.ChainAgnosticContract, error) { +func (d *Provider) getToken(ctx context.Context, ownerAddress persist.Address, url string) (common.ChainAgnosticToken, common.ChainAgnosticContract, error) { req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } resp, err := d.httpClient.Do(req) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } defer resp.Body.Close() var result zoraToken err = json.NewDecoder(resp.Body).Decode(&result) if err != nil { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, err + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, err } tokens, contracts := d.tokensToChainAgnostic(ctx, []zoraToken{result}) if len(tokens) == 0 || len(contracts) == 0 { - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, fmt.Errorf("invalid number of tokens or contracts returned from zora: %d %d", len(tokens), len(contracts)) + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, fmt.Errorf("invalid number of tokens or contracts returned from zora: %d %d", len(tokens), len(contracts)) } if ownerAddress != "" { @@ -488,15 +488,15 @@ func (d *Provider) getToken(ctx context.Context, ownerAddress persist.Address, u return token, contracts[0], nil } } - return multichain.ChainAgnosticToken{}, multichain.ChainAgnosticContract{}, fmt.Errorf("no token found for owner %s", ownerAddress.String()) + return common.ChainAgnosticToken{}, common.ChainAgnosticContract{}, fmt.Errorf("no token found for owner %s", ownerAddress.String()) } return tokens[0], contracts[0], nil } -func (d *Provider) balanceTokensToChainAgnostic(ctx context.Context, tokens []zoraBalanceToken) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract) { - result := make([]multichain.ChainAgnosticToken, 0, len(tokens)) - contracts := map[string]multichain.ChainAgnosticContract{} +func (d *Provider) balanceTokensToChainAgnostic(ctx context.Context, tokens []zoraBalanceToken) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract) { + result := make([]common.ChainAgnosticToken, 0, len(tokens)) + contracts := map[string]common.ChainAgnosticContract{} for _, token := range tokens { converted, err := d.tokenToAgnostic(ctx, token.Token) if err != nil { @@ -524,9 +524,9 @@ func (d *Provider) balanceTokensToChainAgnostic(ctx context.Context, tokens []zo } -func (d *Provider) tokensToChainAgnostic(ctx context.Context, tokens []zoraToken) ([]multichain.ChainAgnosticToken, []multichain.ChainAgnosticContract) { - result := make([]multichain.ChainAgnosticToken, 0, len(tokens)) - contracts := map[string]multichain.ChainAgnosticContract{} +func (d *Provider) tokensToChainAgnostic(ctx context.Context, tokens []zoraToken) ([]common.ChainAgnosticToken, []common.ChainAgnosticContract) { + result := make([]common.ChainAgnosticToken, 0, len(tokens)) + contracts := map[string]common.ChainAgnosticContract{} for _, token := range tokens { converted, err := d.tokenToAgnostic(ctx, token) if err != nil { @@ -549,7 +549,7 @@ func (d *Provider) tokensToChainAgnostic(ctx context.Context, tokens []zoraToken const ipfsFallbackURLFormat = "https://ipfs.decentralized-content.com/ipfs/%s" -func (*Provider) tokenToAgnostic(ctx context.Context, token zoraToken) (multichain.ChainAgnosticToken, error) { +func (*Provider) tokenToAgnostic(ctx context.Context, token zoraToken) (common.ChainAgnosticToken, error) { var tokenType persist.TokenType standard := util.FirstNonEmptyString(token.TokenStandard, token.Mintable.Collection.TokenStandard, token.Collection.TokenStandard) @@ -559,7 +559,7 @@ func (*Provider) tokenToAgnostic(ctx context.Context, token zoraToken) (multicha case "ERC1155": tokenType = persist.TokenTypeERC1155 default: - return multichain.ChainAgnosticToken{}, fmt.Errorf("unknown token standard %s", token.TokenStandard) + return common.ChainAgnosticToken{}, fmt.Errorf("unknown token standard %s", token.TokenStandard) } if token.Metadata == nil { @@ -602,8 +602,8 @@ func (*Provider) tokenToAgnostic(ctx context.Context, token zoraToken) (multicha token.Metadata["image"] = realMedia.Raw } - return multichain.ChainAgnosticToken{ - Descriptors: multichain.ChainAgnosticTokenDescriptors{ + return common.ChainAgnosticToken{ + Descriptors: common.ChainAgnosticTokenDescriptors{ Name: metadataName, Description: metadataDescription, }, @@ -619,10 +619,10 @@ func (*Provider) tokenToAgnostic(ctx context.Context, token zoraToken) (multicha }, nil } -func (d *Provider) contractToChainAgnostic(ctx context.Context, token zoraToken, mergeContract multichain.ChainAgnosticContract) multichain.ChainAgnosticContract { +func (d *Provider) contractToChainAgnostic(ctx context.Context, token zoraToken, mergeContract common.ChainAgnosticContract) common.ChainAgnosticContract { creator := util.FirstNonEmptyString(token.CreatorAddress, token.Mintable.CreatorAddress, mergeContract.Descriptors.OwnerAddress.String()) - return multichain.ChainAgnosticContract{ - Descriptors: multichain.ChainAgnosticContractDescriptors{ + return common.ChainAgnosticContract{ + Descriptors: common.ChainAgnosticContractDescriptors{ Symbol: util.FirstNonEmptyString(token.Collection.Symbol, token.Mintable.Collection.Symbol, mergeContract.Descriptors.Symbol), Name: util.FirstNonEmptyString(token.Collection.Name, token.Mintable.Collection.Name, mergeContract.Descriptors.Name), Description: util.FirstNonEmptyString(token.Collection.Description, token.Mintable.Collection.Description, mergeContract.Descriptors.Description), diff --git a/tokenprocessing/metadata.go b/tokenprocessing/metadata.go index 1f1ea1cec..fdc274cf0 100644 --- a/tokenprocessing/metadata.go +++ b/tokenprocessing/metadata.go @@ -7,6 +7,7 @@ import ( "github.com/mikeydub/go-gallery/service/logger" "github.com/mikeydub/go-gallery/service/multichain" + "github.com/mikeydub/go-gallery/service/multichain/common" "github.com/mikeydub/go-gallery/service/persist" "github.com/mikeydub/go-gallery/util" ) @@ -27,7 +28,7 @@ func (m *MetadataFinder) GetMetadata(ctx context.Context, t persist.TokenIdentif } func (m *MetadataFinder) add(ctx context.Context, t persist.TokenIdentifiers) func() (persist.TokenMetadata, error) { - if _, ok := m.mc.Chains[t.Chain].(multichain.TokenMetadataBatcher); !ok { + if _, ok := m.mc.Chains[t.Chain].(common.TokenMetadataBatcher); !ok { return func() (persist.TokenMetadata, error) { return m.mc.GetTokenMetadataByTokenIdentifiers(ctx, t.ContractAddress, t.TokenID, t.Chain) } @@ -103,8 +104,8 @@ func (b *batch) startTimer(m *MetadataFinder) { func (b *batch) end(m *MetadataFinder) { for chain, tokens := range b.tokens { - tIDs := util.MapWithoutError(tokens, func(t persist.TokenIdentifiers) multichain.ChainAgnosticIdentifiers { - return multichain.ChainAgnosticIdentifiers{ContractAddress: t.ContractAddress, TokenID: t.TokenID} + tIDs := util.MapWithoutError(tokens, func(t persist.TokenIdentifiers) common.ChainAgnosticIdentifiers { + return common.ChainAgnosticIdentifiers{ContractAddress: t.ContractAddress, TokenID: t.TokenID} }) metadata, err := m.mc.GetTokenMetadataByTokenIdentifiersBatch(m.ctx, chain, tIDs) if err != nil {