diff --git a/marketplace/marketplace.gen.go b/marketplace/marketplace.gen.go new file mode 100644 index 00000000..422b3a1d --- /dev/null +++ b/marketplace/marketplace.gen.go @@ -0,0 +1,1560 @@ +// marketplace-api 117ea88649b259b29ebc7b06502884700874b604 +// -- +// Code generated by webrpc-gen@v0.18.3 with golang generator. DO NOT EDIT. +// +// webrpc-gen -schema=marketplace.ridl -target=golang -pkg=marketplaceclient -client -out=./clients/marketplace.gen.go +package marketplace + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "time" + + "github.com/0xsequence/go-sequence/lib/prototyp" +) + +// WebRPC description and code-gen version +func WebRPCVersion() string { + return "v1" +} + +// Schema version of your RIDL schema +func WebRPCSchemaVersion() string { + return "" +} + +// Schema hash generated from your RIDL schema +func WebRPCSchemaHash() string { + return "117ea88649b259b29ebc7b06502884700874b604" +} + +// +// Common types +// + +// TokenMetadata based on 721/1155 standards, as well including some +// fields which are used by OpenSea. +// +// TokenMetadata is RPC type for responding to clients that represents +// the token-level metadata. +type TokenMetadata struct { + TokenID string `json:"tokenId" cbor:"-"` + Name string `json:"name" cbor:"-"` + Description string `json:"description" cbor:"-"` + // url + Image string `json:"image" cbor:"-"` + // non-standard fields we've added for Sequence. Others should adopt + // these too and we should prompt, similar to how `image` field works. + // url + Video string `json:"video,omitempty" cbor:"-"` + // url + Audio string `json:"audio,omitempty" cbor:"-"` + Properties map[string]interface{} `json:"properties" cbor:"-"` + // OpenSea fields + // see https://docs.opensea.io/docs/metadata-standards + // + // NOTE: its a bit unfortunate OpenSea didn't use camelCase, and + // also introduces 'attributes' when 'properties' is actually the correct property name. + // TODO: we could smooth this out / normalize it, but we can leave it for now. + Attributes []map[string]interface{} `json:"attributes" cbor:"-"` + ImageData string `json:"image_data,omitempty" cbor:"-"` + ExternalUrl string `json:"external_url,omitempty" cbor:"-"` + BackgroundColor string `json:"background_color,omitempty" cbor:"-"` + AnimationUrl string `json:"animation_url,omitempty" cbor:"-"` + // + // Misc + // + // decimals is deprecated, but still used by some + Decimals *uint64 `json:"decimals,omitempty" cbor:"-"` + UpdatedAt time.Time `json:"updatedAt" cbor:"-"` + // Assets associated to this token metadata + Assets []*Asset `json:"assets,omitempty" cbor:"-"` +} + +// Asset is a database type used by 'collections' to record static assets for +// a particular 'token' for the token metadata. +// +// db table: assets +type Asset struct { + // asset id + ID uint64 `json:"id" db:"id,omitempty"` + // collection id associated to this asset + CollectionID uint64 `json:"collectionId" db:"collection_id"` + // token id associated to this collection + TokenID prototyp.BigInt `json:"tokenId" db:"token_id"` + // url where we can view the asset contents + // ie. https://metadata.sequence.app/projects/1/collections/1/tokens/1/image + URL string `json:"url" db:"-"` + // metadata field related to TokenMetadata, some field names: + // ['image', 'video', 'audio', 'animation_url', ...] + MetadataField string `json:"metadataField,omitempty" db:"metadata_field"` + // asset details + Filename string `json:"filename,omitempty" db:"filename"` + Filesize uint32 `json:"filesize,omitempty" db:"filesize"` + MimeType string `json:"mimeType,omitempty" db:"mime_type"` + Width *uint16 `json:"width,omitempty" db:"width"` + Height *uint16 `json:"height,omitempty" db:"height"` + UpdatedAt time.Time `json:"updatedAt" db:"updated_at"` +} + +type SortOrder uint32 + +const ( + SortOrder_DESC SortOrder = 0 + SortOrder_ASC SortOrder = 1 +) + +var SortOrder_name = map[uint32]string{ + 0: "DESC", + 1: "ASC", +} + +var SortOrder_value = map[string]uint32{ + "DESC": 0, + "ASC": 1, +} + +func (x SortOrder) String() string { + return SortOrder_name[uint32(x)] +} + +func (x SortOrder) MarshalText() ([]byte, error) { + return []byte(SortOrder_name[uint32(x)]), nil +} + +func (x *SortOrder) UnmarshalText(b []byte) error { + *x = SortOrder(SortOrder_value[string(b)]) + return nil +} + +func (x *SortOrder) Is(values ...SortOrder) bool { + if x == nil { + return false + } + for _, v := range values { + if *x == v { + return true + } + } + return false +} + +type PropertyType uint32 + +const ( + PropertyType_INT PropertyType = 0 + PropertyType_STRING PropertyType = 1 + PropertyType_ARRAY PropertyType = 2 + PropertyType_GENERIC PropertyType = 3 +) + +var PropertyType_name = map[uint32]string{ + 0: "INT", + 1: "STRING", + 2: "ARRAY", + 3: "GENERIC", +} + +var PropertyType_value = map[string]uint32{ + "INT": 0, + "STRING": 1, + "ARRAY": 2, + "GENERIC": 3, +} + +func (x PropertyType) String() string { + return PropertyType_name[uint32(x)] +} + +func (x PropertyType) MarshalText() ([]byte, error) { + return []byte(PropertyType_name[uint32(x)]), nil +} + +func (x *PropertyType) UnmarshalText(b []byte) error { + *x = PropertyType(PropertyType_value[string(b)]) + return nil +} + +func (x *PropertyType) Is(values ...PropertyType) bool { + if x == nil { + return false + } + for _, v := range values { + if *x == v { + return true + } + } + return false +} + +type MarketplaceKind uint32 + +const ( + MarketplaceKind_unknown MarketplaceKind = 0 + MarketplaceKind_orderbook_v1 MarketplaceKind = 1 + MarketplaceKind_orderbook_v2 MarketplaceKind = 2 + MarketplaceKind_opensea MarketplaceKind = 3 + MarketplaceKind_magic_eden MarketplaceKind = 4 + MarketplaceKind_mintify MarketplaceKind = 5 + MarketplaceKind_looks_rare MarketplaceKind = 6 + MarketplaceKind_x2y2 MarketplaceKind = 7 + MarketplaceKind_sudo_swap MarketplaceKind = 8 + MarketplaceKind_coinbase MarketplaceKind = 9 + MarketplaceKind_rarible MarketplaceKind = 10 + MarketplaceKind_nftx MarketplaceKind = 11 + MarketplaceKind_foundation MarketplaceKind = 12 + MarketplaceKind_manifold MarketplaceKind = 13 + MarketplaceKind_zora MarketplaceKind = 14 + MarketplaceKind_blur MarketplaceKind = 15 + MarketplaceKind_super_rare MarketplaceKind = 16 + MarketplaceKind_okx MarketplaceKind = 17 + MarketplaceKind_element MarketplaceKind = 18 + MarketplaceKind_aqua_xyz MarketplaceKind = 19 + MarketplaceKind_auranft_co MarketplaceKind = 20 +) + +var MarketplaceKind_name = map[uint32]string{ + 0: "unknown", + 1: "orderbook_v1", + 2: "orderbook_v2", + 3: "opensea", + 4: "magic_eden", + 5: "mintify", + 6: "looks_rare", + 7: "x2y2", + 8: "sudo_swap", + 9: "coinbase", + 10: "rarible", + 11: "nftx", + 12: "foundation", + 13: "manifold", + 14: "zora", + 15: "blur", + 16: "super_rare", + 17: "okx", + 18: "element", + 19: "aqua_xyz", + 20: "auranft_co", +} + +var MarketplaceKind_value = map[string]uint32{ + "unknown": 0, + "orderbook_v1": 1, + "orderbook_v2": 2, + "opensea": 3, + "magic_eden": 4, + "mintify": 5, + "looks_rare": 6, + "x2y2": 7, + "sudo_swap": 8, + "coinbase": 9, + "rarible": 10, + "nftx": 11, + "foundation": 12, + "manifold": 13, + "zora": 14, + "blur": 15, + "super_rare": 16, + "okx": 17, + "element": 18, + "aqua_xyz": 19, + "auranft_co": 20, +} + +func (x MarketplaceKind) String() string { + return MarketplaceKind_name[uint32(x)] +} + +func (x MarketplaceKind) MarshalText() ([]byte, error) { + return []byte(MarketplaceKind_name[uint32(x)]), nil +} + +func (x *MarketplaceKind) UnmarshalText(b []byte) error { + *x = MarketplaceKind(MarketplaceKind_value[string(b)]) + return nil +} + +func (x *MarketplaceKind) Is(values ...MarketplaceKind) bool { + if x == nil { + return false + } + for _, v := range values { + if *x == v { + return true + } + } + return false +} + +type SourceKind uint32 + +const ( + SourceKind_unknown SourceKind = 0 + SourceKind_external SourceKind = 1 + SourceKind_orderbook_v1 SourceKind = 2 +) + +var SourceKind_name = map[uint32]string{ + 0: "unknown", + 1: "external", + 2: "orderbook_v1", +} + +var SourceKind_value = map[string]uint32{ + "unknown": 0, + "external": 1, + "orderbook_v1": 2, +} + +func (x SourceKind) String() string { + return SourceKind_name[uint32(x)] +} + +func (x SourceKind) MarshalText() ([]byte, error) { + return []byte(SourceKind_name[uint32(x)]), nil +} + +func (x *SourceKind) UnmarshalText(b []byte) error { + *x = SourceKind(SourceKind_value[string(b)]) + return nil +} + +func (x *SourceKind) Is(values ...SourceKind) bool { + if x == nil { + return false + } + for _, v := range values { + if *x == v { + return true + } + } + return false +} + +type OrderSide uint8 + +const ( + OrderSide_unknown OrderSide = 0 + // Ask + OrderSide_listing OrderSide = 1 + // Bid + OrderSide_offer OrderSide = 2 +) + +var OrderSide_name = map[uint8]string{ + 0: "unknown", + 1: "listing", + 2: "offer", +} + +var OrderSide_value = map[string]uint8{ + "unknown": 0, + "listing": 1, + "offer": 2, +} + +func (x OrderSide) String() string { + return OrderSide_name[uint8(x)] +} + +func (x OrderSide) MarshalText() ([]byte, error) { + return []byte(OrderSide_name[uint8(x)]), nil +} + +func (x *OrderSide) UnmarshalText(b []byte) error { + *x = OrderSide(OrderSide_value[string(b)]) + return nil +} + +func (x *OrderSide) Is(values ...OrderSide) bool { + if x == nil { + return false + } + for _, v := range values { + if *x == v { + return true + } + } + return false +} + +type OrderStatus uint8 + +const ( + OrderStatus_unknown OrderStatus = 0 + // Fillable + OrderStatus_active OrderStatus = 1 + // Temporarily unfillable, due to balance / approval + OrderStatus_inactive OrderStatus = 2 + // Permanently unfillable, due to expiry + OrderStatus_expired OrderStatus = 3 + // Permanently unfillable, due to cancellation (by user or protocol) + OrderStatus_cancelled OrderStatus = 4 + // Permanently unfillable, because it's been completely filled + OrderStatus_filled OrderStatus = 5 +) + +var OrderStatus_name = map[uint8]string{ + 0: "unknown", + 1: "active", + 2: "inactive", + 3: "expired", + 4: "cancelled", + 5: "filled", +} + +var OrderStatus_value = map[string]uint8{ + "unknown": 0, + "active": 1, + "inactive": 2, + "expired": 3, + "cancelled": 4, + "filled": 5, +} + +func (x OrderStatus) String() string { + return OrderStatus_name[uint8(x)] +} + +func (x OrderStatus) MarshalText() ([]byte, error) { + return []byte(OrderStatus_name[uint8(x)]), nil +} + +func (x *OrderStatus) UnmarshalText(b []byte) error { + *x = OrderStatus(OrderStatus_value[string(b)]) + return nil +} + +func (x *OrderStatus) Is(values ...OrderStatus) bool { + if x == nil { + return false + } + for _, v := range values { + if *x == v { + return true + } + } + return false +} + +type CollectionStatus uint8 + +const ( + CollectionStatus_unknown CollectionStatus = 0 + CollectionStatus_created CollectionStatus = 1 + CollectionStatus_initializing CollectionStatus = 2 + CollectionStatus_active CollectionStatus = 3 + CollectionStatus_inactive CollectionStatus = 4 +) + +var CollectionStatus_name = map[uint8]string{ + 0: "unknown", + 1: "created", + 2: "initializing", + 3: "active", + 4: "inactive", +} + +var CollectionStatus_value = map[string]uint8{ + "unknown": 0, + "created": 1, + "initializing": 2, + "active": 3, + "inactive": 4, +} + +func (x CollectionStatus) String() string { + return CollectionStatus_name[uint8(x)] +} + +func (x CollectionStatus) MarshalText() ([]byte, error) { + return []byte(CollectionStatus_name[uint8(x)]), nil +} + +func (x *CollectionStatus) UnmarshalText(b []byte) error { + *x = CollectionStatus(CollectionStatus_value[string(b)]) + return nil +} + +func (x *CollectionStatus) Is(values ...CollectionStatus) bool { + if x == nil { + return false + } + for _, v := range values { + if *x == v { + return true + } + } + return false +} + +type ProjectStatus uint8 + +const ( + ProjectStatus_unknown ProjectStatus = 0 + ProjectStatus_active ProjectStatus = 1 + ProjectStatus_inactive ProjectStatus = 2 +) + +var ProjectStatus_name = map[uint8]string{ + 0: "unknown", + 1: "active", + 2: "inactive", +} + +var ProjectStatus_value = map[string]uint8{ + "unknown": 0, + "active": 1, + "inactive": 2, +} + +func (x ProjectStatus) String() string { + return ProjectStatus_name[uint8(x)] +} + +func (x ProjectStatus) MarshalText() ([]byte, error) { + return []byte(ProjectStatus_name[uint8(x)]), nil +} + +func (x *ProjectStatus) UnmarshalText(b []byte) error { + *x = ProjectStatus(ProjectStatus_value[string(b)]) + return nil +} + +func (x *ProjectStatus) Is(values ...ProjectStatus) bool { + if x == nil { + return false + } + for _, v := range values { + if *x == v { + return true + } + } + return false +} + +type CollectibleStatus uint8 + +const ( + CollectibleStatus_unknown CollectibleStatus = 0 + CollectibleStatus_active CollectibleStatus = 1 + CollectibleStatus_inactive CollectibleStatus = 2 +) + +var CollectibleStatus_name = map[uint8]string{ + 0: "unknown", + 1: "active", + 2: "inactive", +} + +var CollectibleStatus_value = map[string]uint8{ + "unknown": 0, + "active": 1, + "inactive": 2, +} + +func (x CollectibleStatus) String() string { + return CollectibleStatus_name[uint8(x)] +} + +func (x CollectibleStatus) MarshalText() ([]byte, error) { + return []byte(CollectibleStatus_name[uint8(x)]), nil +} + +func (x *CollectibleStatus) UnmarshalText(b []byte) error { + *x = CollectibleStatus(CollectibleStatus_value[string(b)]) + return nil +} + +func (x *CollectibleStatus) Is(values ...CollectibleStatus) bool { + if x == nil { + return false + } + for _, v := range values { + if *x == v { + return true + } + } + return false +} + +// Page represents a results page. This can be used both to request a page and +// to store the state of a page. +type Page struct { + // Numbered pages: Page number, this is multiplied by the value of the parameter. + Page uint32 `json:"page,omitempty"` + // Number of items per page + PageSize uint32 `json:"pageSize,omitempty"` + // Indicates if there are more results available + More *bool `json:"more,omitempty"` + // Sorting filter + Sort []*SortBy `json:"sort,omitempty"` +} + +type SortBy struct { + Column string `json:"column"` + Order SortOrder `json:"order"` +} + +// copied from metadata filter +// PropertyFilter +// name -> name of the property, eg: hero +// type -> type of the values of the property, eg: Int, string +// min?, max? used if type is int, gives range of values for filtering +// values? -> if string then array of values, eg: ['Ada', 'Ari', 'Axel', 'Banjo' ...] +// NOTE: When Filter has an array of PropertyFilter, the logic used is an 'and' condition +// whereas if the user selects multiple values inside the PropertyFilter, they logic used is the 'or' condition +// this is to achieve the desired effect opensea had on their filters +type Filter struct { + Text *string `json:"text"` + Properties []*PropertyFilter `json:"properties"` +} + +type PropertyFilter struct { + Name string `json:"name"` + Type PropertyType `json:"type"` + Min *int64 `json:"min"` + Max *int64 `json:"max"` + Values []interface{} `json:"values"` +} + +type CollectiblesFilter struct { + IncludeEmpty bool `json:"includeEmpty"` + SearchText *string `json:"searchText"` + Properties []*PropertyFilter `json:"properties"` + Marketplaces []*MarketplaceKind `json:"marketplaces"` + // filter collectibles owned by given account addresses + InAccounts []string `json:"inAccounts"` + // filter out collectibles owned by given account addresses + NotInAccounts []string `json:"notInAccounts"` + // filter orders created by given account addresses + OrdersCreatedBy []string `json:"ordersCreatedBy"` + // filter out orders created by given account addresses + OrdersNotCreatedBy []string `json:"ordersNotCreatedBy"` +} + +type Order struct { + ID uint64 `json:"id" db:"id,omitempty"` + CollectionID uint64 `json:"collectionId" db:"collection_id,omitempty"` + CollectibleID uint64 `json:"collectibleId" db:"collectible_id,omitempty"` + OrderID string `json:"orderId" db:"order_id"` + Marketplace MarketplaceKind `json:"marketplace" db:"marketplace"` + Source SourceKind `json:"source" db:"source"` + Side OrderSide `json:"side" db:"side"` + Status OrderStatus `json:"status" db:"status"` + ChainID uint64 `json:"chainId" db:"chain_id"` + // contract + ContractAddress prototyp.Hash `json:"contractAddress" db:"contract_address"` + TokenID prototyp.BigInt `json:"tokenId" db:"token_id"` + CreatedBy prototyp.Hash `json:"createdBy" db:"created_by"` + PriceAmount prototyp.BigInt `json:"priceAmount" db:"price_amount"` + PriceAmountFormatted string `json:"priceAmountFormatted"` + PriceAmountNet prototyp.BigInt `json:"priceAmountNet" db:"price_amount_net"` + PriceAmountNetFormatted string `json:"priceAmountNetFormatted"` + PriceCurrencyAddress prototyp.Hash `json:"priceCurrencyAddress" db:"price_currency_address"` + PriceDecimals uint64 `json:"priceDecimals" db:"price_decimals"` + PriceUSD float64 `json:"priceUSD" db:"price_usd"` + QuantityInitial prototyp.BigInt `json:"quantityInitial" db:"qty_initial"` + QuantityInitialFormatted string `json:"quantityInitialFormatted"` + QuantityRemaining prototyp.BigInt `json:"quantityRemaining" db:"qty_remaining"` + QuantityRemainingFormatted string `json:"quantityRemainingFormatted"` + QuantityAvailable prototyp.BigInt `json:"quantityAvailable" db:"qty_available"` + QuantityAvailableFormatted string `json:"quantityAvailableFormatted"` + QuantityDecimals uint64 `json:"quantityDecimals" db:"qty_decimals"` + FeeBPS int64 `json:"feeBps" db:"fee_bps"` + FeeBreakdown []*FeeBreakdown `json:"feeBreakdown" db:"fee_breakdown"` + ValidFrom time.Time `json:"validFrom" db:"valid_from"` + // expiration + ValidUntil time.Time `json:"validUntil" db:"valid_until"` + OrderCreatedAt *time.Time `json:"orderCreatedAt" db:"order_created_at"` + OrderUpdatedAt *time.Time `json:"orderUpdatedAt" db:"order_updated_at"` + CreatedAt time.Time `json:"createdAt" db:"created_at"` + UpdatedAt time.Time `json:"updatedAt" db:"updated_at"` + DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"` +} + +type FeeBreakdown struct { + Kind string `json:"kind"` + RecipientAddress string `json:"recipientAddress"` + Bps int64 `json:"bps"` +} + +type CollectibleListing struct { + Metadata *TokenMetadata `json:"metadata"` + LowestListing *Order `json:"lowestListing"` +} + +type CollectibleOffer struct { + Metadata *TokenMetadata `json:"metadata"` + HighestOffer *Order `json:"highestOffer"` +} + +type OrderFilter struct { + CreatedBy []string `json:"createdBy"` + Marketplace []*MarketplaceKind `json:"marketplace"` +} + +type Activity struct { + Type string `json:"type"` + FromAddress string `json:"fromAddress"` + ToAddress string `json:"toAddress"` + TxHash string `json:"txHash"` + Timestamp int64 `json:"timestamp"` + TokenId string `json:"tokenId"` + TokenImage string `json:"tokenImage"` + TokenName string `json:"tokenName"` + Currency *Currency `json:"currency"` +} + +type Collection struct { + ID uint64 `json:"id" db:"id,omitempty"` + Status CollectionStatus `json:"status" db:"status"` + ChainID uint64 `json:"chainId" db:"chain_id"` + ContractAddress prototyp.Hash `json:"contractAddress" db:"contract_address"` + TokenQuantityDecimals uint64 `json:"tokenQuantityDecimals" db:"token_qty_decimals"` + Config *CollectionConfig `json:"config" db:"config"` + CreatedAt time.Time `json:"createdAt" db:"created_at"` + UpdatedAt time.Time `json:"updatedAt" db:"updated_at"` + DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"` +} + +type CollectionConfig struct { + LastSynced map[string]*CollectionLastSynced `json:"lastSynced"` +} + +type CollectionLastSynced struct { + AllOrders time.Time `json:"allOrders"` + NewOrders time.Time `json:"newOrders"` +} + +type Project struct { + ID uint64 `json:"id" db:"id,omitempty"` + ProjectID uint64 `json:"projectId" db:"project_id"` + CollectionID uint64 `json:"collectionId" db:"collection_id,omitempty"` + ChainID uint64 `json:"chainId" db:"chain_id"` + ContractAddress prototyp.Hash `json:"contractAddress" db:"contract_address"` + Status ProjectStatus `json:"status" db:"status"` + CreatedAt time.Time `json:"createdAt" db:"created_at"` + UpdatedAt time.Time `json:"updatedAt" db:"updated_at"` + DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"` +} + +type Collectible struct { + ID uint64 `json:"id" db:"id,omitempty"` + CollectionID uint64 `json:"collectionId" db:"collection_id,omitempty"` + ChainID uint64 `json:"chainId" db:"chain_id"` + ContractAddress prototyp.Hash `json:"contractAddress" db:"contract_address"` + Status CollectibleStatus `json:"status" db:"status"` + TokenID prototyp.BigInt `json:"tokenId" db:"token_id"` + LowestListingPriceUSD *float64 `json:"lowestListingPriceUsd" db:"lowest_listing_price_usd"` + LowestListingOrderID *uint64 `json:"lowestListingOrderId" db:"lowest_listing_order_id"` + HighestOfferPriceUSD *float64 `json:"highestOfferPriceUsd" db:"highest_offer_price_usd"` + HighestOfferOrderID *uint64 `json:"highestOfferOrderId" db:"highest_offer_order_id"` + CreatedAt time.Time `json:"createdAt" db:"created_at"` + UpdatedAt time.Time `json:"updatedAt" db:"updated_at"` + DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"` +} + +type Currency struct { + ID uint64 `json:"id" db:"id,omitempty"` + ChainID uint64 `json:"chainId" db:"chain_id"` + ContractAddress prototyp.Hash `json:"contractAddress" db:"contract_address"` + Name string `json:"name" db:"name"` + Symbol string `json:"symbol" db:"symbol"` + Decimals uint64 `json:"decimals" db:"decimals"` + ImageURL string `json:"imageUrl" db:"image_url"` + ExchangeRate float64 `json:"exchangeRate" db:"exchange_rate"` + DefaultChainCurrency bool `json:"defaultChainCurrency" db:"default_chain_currency"` + CreditCardSupported bool `json:"creditCardSupported" db:"credit_card_supported"` + CreatedAt time.Time `json:"createdAt" db:"created_at"` + UpdatedAt time.Time `json:"updatedAt" db:"updated_at"` + DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"` +} + +var WebRPCServices = map[string][]string{ + "Admin": { + "CreateCollection", + "GetCollection", + "ListCollections", + "DeleteCollection", + "SyncCollection", + "CreateCurrency", + "CreateCurrencies", + "UpdateCurrency", + "ListCurrencies", + "DeleteCurrency", + }, + "Marketplace": { + "ListCurrencies", + "GetCollectible", + "GetCollectibleLowestOffer", + "GetCollectibleHighestOffer", + "GetCollectibleLowestListing", + "GetCollectibleHighestListing", + "ListCollectibleListings", + "ListCollectibleOffers", + "ListCollectiblesWithLowestListing", + "ListCollectiblesWithHighestOffer", + }, +} + +// +// Server types +// + +type Admin interface { + CreateCollection(ctx context.Context, projectId uint64, contractAddress string) (*Collection, error) + GetCollection(ctx context.Context, projectId uint64, contractAddress string) (*Collection, error) + ListCollections(ctx context.Context, projectId uint64, page *Page) ([]*Collection, *Page, error) + DeleteCollection(ctx context.Context, projectId uint64, contractAddress string) (*Collection, error) + SyncCollection(ctx context.Context, projectId uint64, contractAddress string) error + CreateCurrency(ctx context.Context, currency *Currency) (*Currency, error) + CreateCurrencies(ctx context.Context, currencies []*Currency) (map[string]*Currency, error) + UpdateCurrency(ctx context.Context, currency *Currency) (*Currency, error) + ListCurrencies(ctx context.Context) ([]*Currency, error) + DeleteCurrency(ctx context.Context, chainId uint64, contractAddress string) error +} + +type Marketplace interface { + ListCurrencies(ctx context.Context) ([]*Currency, error) + GetCollectible(ctx context.Context, contractAddress string, tokenId string) (*TokenMetadata, error) + GetCollectibleLowestOffer(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter) (*Order, error) + GetCollectibleHighestOffer(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter) (*Order, error) + GetCollectibleLowestListing(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter) (*Order, error) + GetCollectibleHighestListing(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter) (*Order, error) + ListCollectibleListings(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter, page *Page) ([]*Order, *Page, error) + ListCollectibleOffers(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter, page *Page) ([]*Order, *Page, error) + ListCollectiblesWithLowestListing(ctx context.Context, contractAddress string, filter *CollectiblesFilter, page *Page) ([]*CollectibleListing, *Page, error) + ListCollectiblesWithHighestOffer(ctx context.Context, contractAddress string, filter *CollectiblesFilter, page *Page) ([]*CollectibleOffer, *Page, error) +} + +// +// Client types +// + +type AdminClient interface { + CreateCollection(ctx context.Context, projectId uint64, contractAddress string) (*Collection, error) + GetCollection(ctx context.Context, projectId uint64, contractAddress string) (*Collection, error) + ListCollections(ctx context.Context, projectId uint64, page *Page) ([]*Collection, *Page, error) + DeleteCollection(ctx context.Context, projectId uint64, contractAddress string) (*Collection, error) + SyncCollection(ctx context.Context, projectId uint64, contractAddress string) error + CreateCurrency(ctx context.Context, currency *Currency) (*Currency, error) + CreateCurrencies(ctx context.Context, currencies []*Currency) (map[string]*Currency, error) + UpdateCurrency(ctx context.Context, currency *Currency) (*Currency, error) + ListCurrencies(ctx context.Context) ([]*Currency, error) + DeleteCurrency(ctx context.Context, chainId uint64, contractAddress string) error +} + +type MarketplaceClient interface { + ListCurrencies(ctx context.Context) ([]*Currency, error) + GetCollectible(ctx context.Context, contractAddress string, tokenId string) (*TokenMetadata, error) + GetCollectibleLowestOffer(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter) (*Order, error) + GetCollectibleHighestOffer(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter) (*Order, error) + GetCollectibleLowestListing(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter) (*Order, error) + GetCollectibleHighestListing(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter) (*Order, error) + ListCollectibleListings(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter, page *Page) ([]*Order, *Page, error) + ListCollectibleOffers(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter, page *Page) ([]*Order, *Page, error) + ListCollectiblesWithLowestListing(ctx context.Context, contractAddress string, filter *CollectiblesFilter, page *Page) ([]*CollectibleListing, *Page, error) + ListCollectiblesWithHighestOffer(ctx context.Context, contractAddress string, filter *CollectiblesFilter, page *Page) ([]*CollectibleOffer, *Page, error) +} + +// +// Client +// + +const AdminPathPrefix = "/rpc/Admin/" +const MarketplacePathPrefix = "/rpc/Marketplace/" + +type adminClient struct { + client HTTPClient + urls [10]string +} + +func NewAdminClient(addr string, client HTTPClient) AdminClient { + prefix := urlBase(addr) + AdminPathPrefix + urls := [10]string{ + prefix + "CreateCollection", + prefix + "GetCollection", + prefix + "ListCollections", + prefix + "DeleteCollection", + prefix + "SyncCollection", + prefix + "CreateCurrency", + prefix + "CreateCurrencies", + prefix + "UpdateCurrency", + prefix + "ListCurrencies", + prefix + "DeleteCurrency", + } + return &adminClient{ + client: client, + urls: urls, + } +} + +func (c *adminClient) CreateCollection(ctx context.Context, projectId uint64, contractAddress string) (*Collection, error) { + in := struct { + Arg0 uint64 `json:"projectId"` + Arg1 string `json:"contractAddress"` + }{projectId, contractAddress} + out := struct { + Ret0 *Collection `json:"collection"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[0], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, err +} + +func (c *adminClient) GetCollection(ctx context.Context, projectId uint64, contractAddress string) (*Collection, error) { + in := struct { + Arg0 uint64 `json:"projectId"` + Arg1 string `json:"contractAddress"` + }{projectId, contractAddress} + out := struct { + Ret0 *Collection `json:"collection"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[1], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, err +} + +func (c *adminClient) ListCollections(ctx context.Context, projectId uint64, page *Page) ([]*Collection, *Page, error) { + in := struct { + Arg0 uint64 `json:"projectId"` + Arg1 *Page `json:"page"` + }{projectId, page} + out := struct { + Ret0 []*Collection `json:"collections"` + Ret1 *Page `json:"page"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[2], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, out.Ret1, err +} + +func (c *adminClient) DeleteCollection(ctx context.Context, projectId uint64, contractAddress string) (*Collection, error) { + in := struct { + Arg0 uint64 `json:"projectId"` + Arg1 string `json:"contractAddress"` + }{projectId, contractAddress} + out := struct { + Ret0 *Collection `json:"collection"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[3], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, err +} + +func (c *adminClient) SyncCollection(ctx context.Context, projectId uint64, contractAddress string) error { + in := struct { + Arg0 uint64 `json:"projectId"` + Arg1 string `json:"contractAddress"` + }{projectId, contractAddress} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[4], in, nil) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return err +} + +func (c *adminClient) CreateCurrency(ctx context.Context, currency *Currency) (*Currency, error) { + in := struct { + Arg0 *Currency `json:"currency"` + }{currency} + out := struct { + Ret0 *Currency `json:"currency"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[5], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, err +} + +func (c *adminClient) CreateCurrencies(ctx context.Context, currencies []*Currency) (map[string]*Currency, error) { + in := struct { + Arg0 []*Currency `json:"currencies"` + }{currencies} + out := struct { + Ret0 map[string]*Currency `json:"currency"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[6], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, err +} + +func (c *adminClient) UpdateCurrency(ctx context.Context, currency *Currency) (*Currency, error) { + in := struct { + Arg0 *Currency `json:"currency"` + }{currency} + out := struct { + Ret0 *Currency `json:"currency"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[7], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, err +} + +func (c *adminClient) ListCurrencies(ctx context.Context) ([]*Currency, error) { + out := struct { + Ret0 []*Currency `json:"currencies"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[8], nil, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, err +} + +func (c *adminClient) DeleteCurrency(ctx context.Context, chainId uint64, contractAddress string) error { + in := struct { + Arg0 uint64 `json:"chainId"` + Arg1 string `json:"contractAddress"` + }{chainId, contractAddress} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[9], in, nil) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return err +} + +type marketplaceClient struct { + client HTTPClient + urls [10]string +} + +func NewMarketplaceClient(addr string, client HTTPClient) MarketplaceClient { + prefix := urlBase(addr) + MarketplacePathPrefix + urls := [10]string{ + prefix + "ListCurrencies", + prefix + "GetCollectible", + prefix + "GetCollectibleLowestOffer", + prefix + "GetCollectibleHighestOffer", + prefix + "GetCollectibleLowestListing", + prefix + "GetCollectibleHighestListing", + prefix + "ListCollectibleListings", + prefix + "ListCollectibleOffers", + prefix + "ListCollectiblesWithLowestListing", + prefix + "ListCollectiblesWithHighestOffer", + } + return &marketplaceClient{ + client: client, + urls: urls, + } +} + +func (c *marketplaceClient) ListCurrencies(ctx context.Context) ([]*Currency, error) { + out := struct { + Ret0 []*Currency `json:"currencies"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[0], nil, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, err +} + +func (c *marketplaceClient) GetCollectible(ctx context.Context, contractAddress string, tokenId string) (*TokenMetadata, error) { + in := struct { + Arg0 string `json:"contractAddress"` + Arg1 string `json:"tokenId"` + }{contractAddress, tokenId} + out := struct { + Ret0 *TokenMetadata `json:"metadata"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[1], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, err +} + +func (c *marketplaceClient) GetCollectibleLowestOffer(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter) (*Order, error) { + in := struct { + Arg0 string `json:"contractAddress"` + Arg1 string `json:"tokenId"` + Arg2 *OrderFilter `json:"filter"` + }{contractAddress, tokenId, filter} + out := struct { + Ret0 *Order `json:"order"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[2], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, err +} + +func (c *marketplaceClient) GetCollectibleHighestOffer(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter) (*Order, error) { + in := struct { + Arg0 string `json:"contractAddress"` + Arg1 string `json:"tokenId"` + Arg2 *OrderFilter `json:"filter"` + }{contractAddress, tokenId, filter} + out := struct { + Ret0 *Order `json:"order"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[3], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, err +} + +func (c *marketplaceClient) GetCollectibleLowestListing(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter) (*Order, error) { + in := struct { + Arg0 string `json:"contractAddress"` + Arg1 string `json:"tokenId"` + Arg2 *OrderFilter `json:"filter"` + }{contractAddress, tokenId, filter} + out := struct { + Ret0 *Order `json:"order"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[4], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, err +} + +func (c *marketplaceClient) GetCollectibleHighestListing(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter) (*Order, error) { + in := struct { + Arg0 string `json:"contractAddress"` + Arg1 string `json:"tokenId"` + Arg2 *OrderFilter `json:"filter"` + }{contractAddress, tokenId, filter} + out := struct { + Ret0 *Order `json:"order"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[5], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, err +} + +func (c *marketplaceClient) ListCollectibleListings(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter, page *Page) ([]*Order, *Page, error) { + in := struct { + Arg0 string `json:"contractAddress"` + Arg1 string `json:"tokenId"` + Arg2 *OrderFilter `json:"filter"` + Arg3 *Page `json:"page"` + }{contractAddress, tokenId, filter, page} + out := struct { + Ret0 []*Order `json:"listings"` + Ret1 *Page `json:"page"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[6], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, out.Ret1, err +} + +func (c *marketplaceClient) ListCollectibleOffers(ctx context.Context, contractAddress string, tokenId string, filter *OrderFilter, page *Page) ([]*Order, *Page, error) { + in := struct { + Arg0 string `json:"contractAddress"` + Arg1 string `json:"tokenId"` + Arg2 *OrderFilter `json:"filter"` + Arg3 *Page `json:"page"` + }{contractAddress, tokenId, filter, page} + out := struct { + Ret0 []*Order `json:"offers"` + Ret1 *Page `json:"page"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[7], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, out.Ret1, err +} + +func (c *marketplaceClient) ListCollectiblesWithLowestListing(ctx context.Context, contractAddress string, filter *CollectiblesFilter, page *Page) ([]*CollectibleListing, *Page, error) { + in := struct { + Arg0 string `json:"contractAddress"` + Arg1 *CollectiblesFilter `json:"filter"` + Arg2 *Page `json:"page"` + }{contractAddress, filter, page} + out := struct { + Ret0 []*CollectibleListing `json:"collectibles"` + Ret1 *Page `json:"page"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[8], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, out.Ret1, err +} + +func (c *marketplaceClient) ListCollectiblesWithHighestOffer(ctx context.Context, contractAddress string, filter *CollectiblesFilter, page *Page) ([]*CollectibleOffer, *Page, error) { + in := struct { + Arg0 string `json:"contractAddress"` + Arg1 *CollectiblesFilter `json:"filter"` + Arg2 *Page `json:"page"` + }{contractAddress, filter, page} + out := struct { + Ret0 []*CollectibleOffer `json:"collectibles"` + Ret1 *Page `json:"page"` + }{} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[9], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return out.Ret0, out.Ret1, err +} + +// HTTPClient is the interface used by generated clients to send HTTP requests. +// It is fulfilled by *(net/http).Client, which is sufficient for most users. +// Users can provide their own implementation for special retry policies. +type HTTPClient interface { + Do(req *http.Request) (*http.Response, error) +} + +// urlBase helps ensure that addr specifies a scheme. If it is unparsable +// as a URL, it returns addr unchanged. +func urlBase(addr string) string { + // If the addr specifies a scheme, use it. If not, default to + // http. If url.Parse fails on it, return it unchanged. + url, err := url.Parse(addr) + if err != nil { + return addr + } + if url.Scheme == "" { + url.Scheme = "http" + } + return url.String() +} + +// newRequest makes an http.Request from a client, adding common headers. +func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType string) (*http.Request, error) { + req, err := http.NewRequestWithContext(ctx, "POST", url, reqBody) + if err != nil { + return nil, err + } + req.Header.Set("Accept", contentType) + req.Header.Set("Content-Type", contentType) + if headers, ok := HTTPRequestHeaders(ctx); ok { + for k := range headers { + for _, v := range headers[k] { + req.Header.Add(k, v) + } + } + } + return req, nil +} + +// doHTTPRequest is common code to make a request to the remote service. +func doHTTPRequest(ctx context.Context, client HTTPClient, url string, in, out interface{}) (*http.Response, error) { + reqBody, err := json.Marshal(in) + if err != nil { + return nil, ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to marshal JSON body: %w", err)) + } + if err = ctx.Err(); err != nil { + return nil, ErrWebrpcRequestFailed.WithCause(fmt.Errorf("aborted because context was done: %w", err)) + } + + req, err := newRequest(ctx, url, bytes.NewBuffer(reqBody), "application/json") + if err != nil { + return nil, ErrWebrpcRequestFailed.WithCause(fmt.Errorf("could not build request: %w", err)) + } + + resp, err := client.Do(req) + if err != nil { + return nil, ErrWebrpcRequestFailed.WithCause(err) + } + + if resp.StatusCode != 200 { + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to read server error response body: %w", err)) + } + + var rpcErr WebRPCError + if err := json.Unmarshal(respBody, &rpcErr); err != nil { + return nil, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to unmarshal server error: %w", err)) + } + if rpcErr.Cause != "" { + rpcErr.cause = errors.New(rpcErr.Cause) + } + return nil, rpcErr + } + + if out != nil { + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to read response body: %w", err)) + } + + err = json.Unmarshal(respBody, &out) + if err != nil { + return nil, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to unmarshal JSON response body: %w", err)) + } + } + + return resp, nil +} + +func WithHTTPRequestHeaders(ctx context.Context, h http.Header) (context.Context, error) { + if _, ok := h["Accept"]; ok { + return nil, errors.New("provided header cannot set Accept") + } + if _, ok := h["Content-Type"]; ok { + return nil, errors.New("provided header cannot set Content-Type") + } + + copied := make(http.Header, len(h)) + for k, vv := range h { + if vv == nil { + copied[k] = nil + continue + } + copied[k] = make([]string, len(vv)) + copy(copied[k], vv) + } + + return context.WithValue(ctx, HTTPClientRequestHeadersCtxKey, copied), nil +} + +func HTTPRequestHeaders(ctx context.Context) (http.Header, bool) { + h, ok := ctx.Value(HTTPClientRequestHeadersCtxKey).(http.Header) + return h, ok +} + +// +// Helpers +// + +type contextKey struct { + name string +} + +func (k *contextKey) String() string { + return "webrpc context value " + k.name +} + +var ( + HTTPClientRequestHeadersCtxKey = &contextKey{"HTTPClientRequestHeaders"} + HTTPRequestCtxKey = &contextKey{"HTTPRequest"} + + ServiceNameCtxKey = &contextKey{"ServiceName"} + + MethodNameCtxKey = &contextKey{"MethodName"} +) + +func ServiceNameFromContext(ctx context.Context) string { + service, _ := ctx.Value(ServiceNameCtxKey).(string) + return service +} + +func MethodNameFromContext(ctx context.Context) string { + method, _ := ctx.Value(MethodNameCtxKey).(string) + return method +} + +func RequestFromContext(ctx context.Context) *http.Request { + r, _ := ctx.Value(HTTPRequestCtxKey).(*http.Request) + return r +} + +// +// Errors +// + +type WebRPCError struct { + Name string `json:"error"` + Code int `json:"code"` + Message string `json:"msg"` + Cause string `json:"cause,omitempty"` + HTTPStatus int `json:"status"` + cause error +} + +var _ error = WebRPCError{} + +func (e WebRPCError) Error() string { + if e.cause != nil { + return fmt.Sprintf("%s %d: %s: %v", e.Name, e.Code, e.Message, e.cause) + } + return fmt.Sprintf("%s %d: %s", e.Name, e.Code, e.Message) +} + +func (e WebRPCError) Is(target error) bool { + if target == nil { + return false + } + if rpcErr, ok := target.(WebRPCError); ok { + return rpcErr.Code == e.Code + } + return errors.Is(e.cause, target) +} + +func (e WebRPCError) Unwrap() error { + return e.cause +} + +func (e WebRPCError) WithCause(cause error) WebRPCError { + err := e + err.cause = cause + err.Cause = cause.Error() + return err +} + +func (e WebRPCError) WithCausef(format string, args ...interface{}) WebRPCError { + cause := fmt.Errorf(format, args...) + err := e + err.cause = cause + err.Cause = cause.Error() + return err +} + +// Deprecated: Use .WithCause() method on WebRPCError. +func ErrorWithCause(rpcErr WebRPCError, cause error) WebRPCError { + return rpcErr.WithCause(cause) +} + +// Webrpc errors +var ( + ErrWebrpcEndpoint = WebRPCError{Code: 0, Name: "WebrpcEndpoint", Message: "endpoint error", HTTPStatus: 400} + ErrWebrpcRequestFailed = WebRPCError{Code: -1, Name: "WebrpcRequestFailed", Message: "request failed", HTTPStatus: 400} + ErrWebrpcBadRoute = WebRPCError{Code: -2, Name: "WebrpcBadRoute", Message: "bad route", HTTPStatus: 404} + ErrWebrpcBadMethod = WebRPCError{Code: -3, Name: "WebrpcBadMethod", Message: "bad method", HTTPStatus: 405} + ErrWebrpcBadRequest = WebRPCError{Code: -4, Name: "WebrpcBadRequest", Message: "bad request", HTTPStatus: 400} + ErrWebrpcBadResponse = WebRPCError{Code: -5, Name: "WebrpcBadResponse", Message: "bad response", HTTPStatus: 500} + ErrWebrpcServerPanic = WebRPCError{Code: -6, Name: "WebrpcServerPanic", Message: "server panic", HTTPStatus: 500} + ErrWebrpcInternalError = WebRPCError{Code: -7, Name: "WebrpcInternalError", Message: "internal error", HTTPStatus: 500} + ErrWebrpcClientDisconnected = WebRPCError{Code: -8, Name: "WebrpcClientDisconnected", Message: "client disconnected", HTTPStatus: 400} + ErrWebrpcStreamLost = WebRPCError{Code: -9, Name: "WebrpcStreamLost", Message: "stream lost", HTTPStatus: 400} + ErrWebrpcStreamFinished = WebRPCError{Code: -10, Name: "WebrpcStreamFinished", Message: "stream finished", HTTPStatus: 200} +) + +// Schema errors +var ( + ErrUnauthorized = WebRPCError{Code: 1000, Name: "Unauthorized", Message: "Unauthorized access", HTTPStatus: 401} + ErrPermissionDenied = WebRPCError{Code: 1001, Name: "PermissionDenied", Message: "Permission denied", HTTPStatus: 403} + ErrSessionExpired = WebRPCError{Code: 1002, Name: "SessionExpired", Message: "Session expired", HTTPStatus: 403} + ErrMethodNotFound = WebRPCError{Code: 1003, Name: "MethodNotFound", Message: "Method not found", HTTPStatus: 404} + ErrTimeout = WebRPCError{Code: 2000, Name: "Timeout", Message: "Request timed out", HTTPStatus: 408} + ErrInvalidArgument = WebRPCError{Code: 2001, Name: "InvalidArgument", Message: "Invalid argument", HTTPStatus: 400} + ErrNotFound = WebRPCError{Code: 3000, Name: "NotFound", Message: "Resource not found", HTTPStatus: 400} + ErrUserNotFound = WebRPCError{Code: 3001, Name: "UserNotFound", Message: "User not found", HTTPStatus: 400} + ErrProjectNotFound = WebRPCError{Code: 3002, Name: "ProjectNotFound", Message: "Project not found", HTTPStatus: 400} + ErrInvalidTier = WebRPCError{Code: 3003, Name: "InvalidTier", Message: "Invalid subscription tier", HTTPStatus: 400} + ErrProjectLimitReached = WebRPCError{Code: 3005, Name: "ProjectLimitReached", Message: "Project limit reached", HTTPStatus: 402} + ErrNotImplemented = WebRPCError{Code: 9999, Name: "NotImplemented", Message: "Not Implemented", HTTPStatus: 500} +) diff --git a/marketplace/marketplace.go b/marketplace/marketplace.go new file mode 100644 index 00000000..a88edba4 --- /dev/null +++ b/marketplace/marketplace.go @@ -0,0 +1,57 @@ +package marketplace + +import ( + "fmt" + "net/http" +) + +type Options struct { + MarketplaceApiUrl string + JWTAuthToken string + HTTPClient HTTPClient +} + +func NewMarketplaceAdmin(projectAccessKey string, chainHandle string, options ...Options) AdminClient { + opts := Options{} + if len(options) > 0 { + opts = options[0] + } + + client := &httpclient{ + client: opts.HTTPClient, + projectAccessKey: projectAccessKey, + } + if opts.HTTPClient == nil { + client.client = http.DefaultClient + } + if opts.JWTAuthToken != "" { + client.jwtAuthHeader = fmt.Sprintf("BEARER %s", opts.JWTAuthToken) + } + + // prod: https://marketplace-api.sequence.app + // dev: https://dev-marketplace-api.sequence.app + apiUrl := fmt.Sprintf("https://marketplace-api.sequence.app/%s", chainHandle) + if opts.MarketplaceApiUrl != "" { + apiUrl = opts.MarketplaceApiUrl + "/" + chainHandle + } + + return NewAdminClient(apiUrl, client.client) +} + +type httpclient struct { + client HTTPClient + jwtAuthHeader string + projectAccessKey string +} + +func (c *httpclient) Do(req *http.Request) (*http.Response, error) { + if c.projectAccessKey != "" { + req.Header.Set("X-Access-Key", c.projectAccessKey) + } + + if c.jwtAuthHeader != "" { + req.Header.Set("Authorization", fmt.Sprintf("BEARER %s", c.jwtAuthHeader)) + } + + return c.client.Do(req) +}