Skip to content

Commit 0afd503

Browse files
authored
fix: Clickable "Upcoming Launches" cards #460 + updates to launchpad [👀] (#463)
* Don't show pagination buttons if collection is less than 5 * If collection is not mintable yet, send user to they twitter page * Clickable "Upcoming Launches" cards #460 + updates to launchpad * Fix last item of the carousel border * Make launchpad carousels into galleries * Make minted % to use round instead of floor * Don't show empty sections * Allow to be sorted by date General sorting improvements Hide TNS from ended status Speed up price look up when loading lauchpad * 🤖 generate graphql code * ethereum.go cache busting + MintState aware query * 🤖 GraphQL code generation * Fix Max supply card in Eth network * Upcoming cards get twitter url from airtable and use that as pre mint page. * reviewer changes * remove this unexpected "(" from the JSX
1 parent 819099c commit 0afd503

File tree

19 files changed

+1994
-487
lines changed

19 files changed

+1994
-487
lines changed

.graphqlconfig

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "TheGraph GraphQL Schema",
3+
"schemaPath": "schema.graphql",
4+
"extensions": {
5+
"endpoints": {
6+
"TheGraph GraphQL Endpoint MainNet": {
7+
"url": "https://api.studio.thegraph.com/query/40379/teritori-mainnet/v1",
8+
"headers": {
9+
"user-agent": "JS GraphQL"
10+
},
11+
"introspect": true
12+
}
13+
}
14+
}
15+
}

api/marketplace/v1/marketplace.proto

+5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ enum Sort {
1919
SORTING_PRICE = 1;
2020
SORTING_VOLUME = 2;
2121
SORTING_MARKET_CAP = 3;
22+
SORTING_CREATED_AT = 4;
2223
}
2324

2425
enum SortDirection {
@@ -71,6 +72,10 @@ message Collection {
7172
string volume_denom = 9;
7273
string creator_id = 10;
7374
bool secondary_during_mint = 12;
75+
string website_url = 13;
76+
string twitter_url = 14;
77+
uint64 floor_price = 15;
78+
int64 max_supply = 16;
7479
}
7580

7681
message CollectionStats {

go/internal/airtable_fetcher/upcoming.go

+12
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ func (c *Client) FetchUpcomingLaunches(logger *zap.Logger) ([]*marketplacepb.Col
3535
continue
3636
}
3737

38+
websiteUrl, ok := record.Fields["WebsiteURL"].(string)
39+
if !ok {
40+
websiteUrl = ""
41+
}
42+
43+
twitterUrl, ok := record.Fields["TwitterURL"].(string)
44+
if !ok {
45+
twitterUrl = ""
46+
}
47+
3848
pfpArray, ok := record.Fields["CollectionPFP"].([]interface{})
3949
if !ok {
4050
continue
@@ -57,6 +67,8 @@ func (c *Client) FetchUpcomingLaunches(logger *zap.Logger) ([]*marketplacepb.Col
5767
ImageUri: imageURI,
5868
CollectionName: collectionName,
5969
CreatorName: creatorName,
70+
TwitterUrl: twitterUrl,
71+
WebsiteUrl: websiteUrl,
6072
})
6173
}
6274
return upcomingLaunches, nil

go/internal/ethereum/ethereum.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ type Volume struct {
4444
volume int64
4545
}
4646

47-
func (p *Provider) GetCollections(ctx context.Context, networkId string) ([]marketplacepb.Collection, error) {
48-
cacheKey := fmt.Sprintf("col_%s", networkId)
47+
func (p *Provider) GetCollections(ctx context.Context, networkId string, req *marketplacepb.CollectionsRequest) ([]marketplacepb.Collection, error) {
48+
cacheKey := fmt.Sprintf("col_%s_mint_%s", networkId, req.GetMintState())
4949
data, ok := p.cache.Get(cacheKey)
5050
if ok {
5151
return data.([]marketplacepb.Collection), nil
@@ -80,6 +80,9 @@ func (p *Provider) GetCollections(ctx context.Context, networkId string) ([]mark
8080
// Fix: currently it does not support multiple denoms
8181
res := make([]marketplacepb.Collection, 0, len(collections.NftContracts))
8282
for _, contract := range collections.NftContracts {
83+
if req.GetMintState() == marketplacepb.MintState_MINT_STATE_ENDED && volumeByCollection[contract.Id].volume == 0 {
84+
continue
85+
}
8386
res = append(res, marketplacepb.Collection{
8487
NetworkId: networkId,
8588
Id: string(network.CollectionID(contract.Minter)),

go/internal/indexerdb/collection.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package indexerdb
22

3-
import "github.com/TERITORI/teritori-dapp/go/pkg/networks"
3+
import (
4+
"github.com/TERITORI/teritori-dapp/go/pkg/networks"
5+
"time"
6+
)
47

58
type Collection struct {
69
// ID is network-dependent
@@ -13,6 +16,7 @@ type Collection struct {
1316
MaxSupply int
1417
SecondaryDuringMint bool
1518
Paused bool
19+
Time time.Time
1620

1721
// "has one" relations
1822
TeritoriCollection *TeritoriCollection
@@ -26,4 +30,6 @@ type TeritoriCollection struct {
2630
MintContractAddress string `gorm:"primaryKey"`
2731
NFTContractAddress string
2832
CreatorAddress string
33+
Price int64
34+
Denom string
2935
}

go/internal/indexerhandler/bunker_minter.go

+15
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ func (h *Handler) handleInstantiateBunker(e *Message, contractAddress string, in
4040
maxSupply = -1
4141
}
4242

43+
price, err := strconv.Atoi(minterInstantiateMsg.NftPriceAmount)
44+
if err != nil {
45+
h.logger.Error("failed to parse nft price", zap.Error(err))
46+
price = -1
47+
}
48+
4349
secondaryDuringMint := false
4450
if sdm, ok := minterInstantiateMsg.SecondaryDuringMint.(bool); ok {
4551
secondaryDuringMint = sdm
@@ -52,17 +58,26 @@ func (h *Handler) handleInstantiateBunker(e *Message, contractAddress string, in
5258
return errors.Wrap(err, "failed to get network from collectionID")
5359
}
5460

61+
// get block time
62+
blockTime, err := e.GetBlockTime()
63+
if err != nil {
64+
return errors.Wrap(err, "failed to get block time")
65+
}
66+
5567
if err := h.db.Create(&indexerdb.Collection{
5668
ID: collectionId,
5769
NetworkId: network.GetBase().ID,
5870
Name: minterInstantiateMsg.NftName,
5971
ImageURI: metadata.ImageURI,
6072
MaxSupply: maxSupply,
6173
SecondaryDuringMint: secondaryDuringMint,
74+
Time: blockTime,
6275
TeritoriCollection: &indexerdb.TeritoriCollection{
6376
MintContractAddress: contractAddress,
6477
NFTContractAddress: nftAddr,
6578
CreatorAddress: instantiateMsg.Sender,
79+
Price: int64(price),
80+
Denom: minterInstantiateMsg.PriceDenom,
6681
},
6782
}).Error; err != nil {
6883
return errors.Wrap(err, "failed to create collection")

go/pkg/marketplace/marketplace_service.go

+31-5
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ type DBCollectionWithExtra struct {
6969
Volume string
7070
MintContractAddress string
7171
CreatorAddress string
72+
Price uint64
73+
MaxSupply int64
7274
SecondaryDuringMint bool
7375
}
7476

@@ -116,15 +118,36 @@ func (s *MarkteplaceService) Collections(req *marketplacepb.CollectionsRequest,
116118
case marketplacepb.MintState_MINT_STATE_RUNNING:
117119
where = "where c.paused = false and c.max_supply != -1 and (select count from count_by_collection where collection_id = c.id) != c.max_supply"
118120
case marketplacepb.MintState_MINT_STATE_ENDED:
119-
where = "where c.max_supply = -1 or (select count from count_by_collection where collection_id = c.id) = c.max_supply"
121+
where = "where (select count from count_by_collection where collection_id = c.id) = c.max_supply"
122+
}
123+
orderDirection := ""
124+
switch req.GetSortDirection() {
125+
case marketplacepb.SortDirection_SORT_DIRECTION_UNSPECIFIED:
126+
orderDirection = ""
127+
case marketplacepb.SortDirection_SORT_DIRECTION_ASCENDING:
128+
orderDirection = " ASC "
129+
case marketplacepb.SortDirection_SORT_DIRECTION_DESCENDING:
130+
orderDirection = " DESC "
131+
}
132+
orderSQL := ""
133+
switch req.GetSort() {
134+
case marketplacepb.Sort_SORTING_PRICE:
135+
where = where + "AND tc.denom = utori" // not mixed denoms allowed !
136+
orderSQL = "tc.price" + orderDirection
137+
case marketplacepb.Sort_SORTING_VOLUME:
138+
orderSQL = "volume " + orderDirection + ", id ASC"
139+
case marketplacepb.Sort_SORTING_CREATED_AT:
140+
orderSQL = "c.time " + orderDirection
141+
case marketplacepb.Sort_SORTING_UNSPECIFIED:
142+
orderSQL = "volume DESC, id ASC"
120143
}
121144

122145
err := s.conf.IndexerDB.Raw(fmt.Sprintf(`
123146
WITH count_by_collection AS (
124147
SELECT count(1), collection_id FROM nfts GROUP BY nfts.collection_id
125148
),
126149
tori_collections AS (
127-
SELECT c.*, tc.mint_contract_address, tc.creator_address FROM collections AS c
150+
SELECT c.*, tc.* FROM collections AS c
128151
INNER JOIN teritori_collections tc ON tc.collection_id = c.id
129152
%s
130153
AND tc.mint_contract_address IN ?
@@ -145,14 +168,15 @@ func (s *MarkteplaceService) Collections(req *marketplacepb.CollectionsRequest,
145168
INNER JOIN nft_by_collection nbc ON nbc.nft_id = t.nft_id
146169
GROUP BY nbc.id
147170
)
148-
SELECT tc.*, COALESCE((SELECT tbc.volume FROM trades_by_collection tbc WHERE tbc.id = tc.id), 0) volume
171+
SELECT tc.*, COALESCE((SELECT tbc.volume FROM trades_by_collection tbc WHERE tbc.id = tc.id), 0) volume
149172
FROM tori_collections tc
150-
ORDER BY volume DESC, id ASC
173+
ORDER BY ?
151174
LIMIT ?
152175
OFFSET ?
153176
`, where),
154177
s.conf.Whitelist,
155178
time.Now().AddDate(0, 0, -30),
179+
orderSQL,
156180
limit,
157181
offset,
158182
).Scan(&collections).Error
@@ -171,6 +195,8 @@ func (s *MarkteplaceService) Collections(req *marketplacepb.CollectionsRequest,
171195
Volume: c.Volume,
172196
CreatorId: string(network.UserID(c.CreatorAddress)),
173197
SecondaryDuringMint: c.SecondaryDuringMint,
198+
FloorPrice: c.Price,
199+
MaxSupply: c.MaxSupply,
174200
}}); err != nil {
175201
return errors.Wrap(err, "failed to send collection")
176202
}
@@ -179,7 +205,7 @@ func (s *MarkteplaceService) Collections(req *marketplacepb.CollectionsRequest,
179205
return nil
180206

181207
case *networks.EthereumNetwork:
182-
collections, err := s.ethereumProvider.GetCollections(srv.Context(), networkID)
208+
collections, err := s.ethereumProvider.GetCollections(srv.Context(), networkID, req)
183209
if err != nil {
184210
return errors.Wrap(err, "failed to query database")
185211
}

0 commit comments

Comments
 (0)