Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(grc20-launchpad): UI implementation #1276

Merged
merged 44 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
7e8d045
feat(launchpad-grc20): create new screen & setup navigation
MikaelVallenet Sep 12, 2024
0888072
feat(launchpad-grc20): add launchpadERC20 banner & description text
MikaelVallenet Sep 13, 2024
0dddf28
feat(launchpad-grc20): transform launchpadButton into a generic Large…
MikaelVallenet Sep 13, 2024
494035a
style(launchpad-grc20): new banner
MikaelVallenet Sep 13, 2024
ba717f0
feat(launchpad-grc20): add empty tokens, airdrops & sales page
MikaelVallenet Sep 13, 2024
1cb1821
ci(launchpad-grc20): run eslint --fix
MikaelVallenet Sep 13, 2024
5b39cf7
ci(launchpad-grc20): resolve @hthieu1110 suggestions & add new hook u…
MikaelVallenet Sep 13, 2024
3668599
ci(launchpad-grc20): add network project launchpad erc20 in gno-dev &…
MikaelVallenet Sep 16, 2024
4e402cb
feat(launchpad-g/erc20): refactor flow card from TNS service & add 3 …
MikaelVallenet Sep 16, 2024
c335353
wip(launchpad-g/erc20): add recent created tokens table
MikaelVallenet Sep 17, 2024
fd5b4e5
Merge branch 'main' into gno-launchpad-erc20-UI
MikaelVallenet Sep 17, 2024
5cc0244
feat(launchpad-g/erc20): add gno function to return 10 last tokens as…
MikaelVallenet Sep 17, 2024
ed063e9
feat(launchpad-g/erc20): add hooks useLastTokens to retrieve last tok…
MikaelVallenet Sep 18, 2024
7c478e2
feat(launchpad-g/erc20): retrieve last tokens from chain & display it
MikaelVallenet Sep 18, 2024
97cd02b
feat(launchpad-g/erc20): first step of the token creation form
MikaelVallenet Sep 19, 2024
b8c6078
fix(launchpad-g/erc20): fix various bugs from token creation, add det…
MikaelVallenet Sep 19, 2024
d2422eb
feat(launchpad-g/erc20): add token creation tx & redirect after creation
MikaelVallenet Sep 19, 2024
134dfeb
feat(launchpad-g/erc20): add function get last airdrops & sales in js…
MikaelVallenet Sep 20, 2024
02dc5b7
feat(launchpad-g/erc20): add airdrops & sales pages
MikaelVallenet Sep 20, 2024
726679a
feat(launchpad-g/erc20): add airdrops & sales creation flow
MikaelVallenet Sep 20, 2024
10c9e3c
fix(launchpad-g/erc20): fix unused exports
MikaelVallenet Sep 20, 2024
14f2b8a
Merge branch 'main' into gno-launchpad-erc20-UI
MikaelVallenet Sep 20, 2024
a0ddbf3
fix(launchpad-g/erc20): use tertiary box instead of box
MikaelVallenet Sep 23, 2024
b55404e
fix(launchpad-g/erc20): use well-known breakpoints in launchpad banner
MikaelVallenet Sep 23, 2024
e38dcba
fix(launchpad-g/erc20): use camelCase for pretty functions
MikaelVallenet Sep 23, 2024
bff1a7d
fix(launchpad-g/erc20): move all zod schema to form.ts in utils folder
MikaelVallenet Sep 23, 2024
4649e86
Update packages/utils/navigation.ts
MikaelVallenet Sep 23, 2024
3a78bcc
Update packages/utils/navigation.ts
MikaelVallenet Sep 23, 2024
753c337
Update packages/utils/navigation.ts
MikaelVallenet Sep 23, 2024
af068a1
fix(launchpad-g/erc20): use control & rules w/ react hook form
MikaelVallenet Sep 23, 2024
f1f81a4
Update packages/screens/LaunchpadERC20/LaunchpadERC20Sales/LaunchpadE…
MikaelVallenet Sep 23, 2024
b19fbf2
Update packages/screens/LaunchpadERC20/LaunchpadERC20Tokens/Launchpad…
MikaelVallenet Sep 23, 2024
8e21a48
Update packages/screens/LaunchpadERC20/LaunchpadERCAirdrops/Launchpad…
MikaelVallenet Sep 23, 2024
cba45c5
chore(launchpad-g/erc20): rename create token/airdrop/sale screens files
MikaelVallenet Sep 23, 2024
c84dc0a
fix(launchpad-g/erc20): use onBackPress property from screenContainer…
MikaelVallenet Sep 23, 2024
cb5f7e7
fix(launchpad-g/erc20): add devOnly to launchpad
MikaelVallenet Sep 23, 2024
c8fa0b8
Merge branch 'main' into gno-launchpad-erc20-UI
MikaelVallenet Sep 24, 2024
b06bcb6
fix(launchpad-g/erc20): add datetime picker
MikaelVallenet Sep 24, 2024
b93837d
feat(launchpad-g/erc20): compute merkle root from csv files
MikaelVallenet Sep 24, 2024
b22a1f1
feat(launchpad-g/erc20): compute merkle root from csv files
MikaelVallenet Sep 24, 2024
8a58d4d
Update packages/screens/LaunchpadERC20/LaunchpadERCAirdrops/Launchpad…
MikaelVallenet Sep 25, 2024
fe04186
fix(launchpad-g/erc20): add label & sublabel for csv input & set the …
MikaelVallenet Sep 25, 2024
af90977
Merge branch 'gno-launchpad-erc20-UI' of github.com:TERITORI/teritori…
MikaelVallenet Sep 25, 2024
00ec5d4
fix(launchpad-g/erc20): generate networks.json
MikaelVallenet Sep 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/banners/launchpadERC20.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 38 additions & 8 deletions gno/r/launchpad_grc20/airdrop_grc20.gno
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@ package launchpad_grc20
import (
"encoding/hex"
"std"
"strconv"
"time"

"gno.land/p/demo/avl"
"gno.land/p/demo/json"
"gno.land/p/demo/merkle"
"gno.land/p/demo/seqid"
"gno.land/p/demo/ufmt"
"gno.land/p/teritori/jsonutil"
)

type Airdrop struct {
token *Token
id seqid.ID
merkleRoot string
startTimestamp int64
endTimestamp int64
Expand Down Expand Up @@ -52,16 +55,18 @@ func NewAirdrop(tokenName, merkleRoot string, amountPerAddr uint64, startTimesta
panic("invalid timestamps, start must be before end")
}

airdropID := nextAirdropID.Next()

airdrop := Airdrop{
token: token,
id: airdropID,
merkleRoot: merkleRoot,
startTimestamp: startTimestamp,
endTimestamp: endTimestamp,
amountPerAddr: amountPerAddr,
alreadyClaimed: avl.NewTree(),
}

airdropID := nextAirdropID.Next()
token.AirdropsIDs = append(token.AirdropsIDs, airdropID)

airdrops.Set(airdropID.String(), &airdrop)
Expand Down Expand Up @@ -110,6 +115,27 @@ func Claim(airdropID uint64, proofs []merkle.Node) {
airdrop.alreadyClaimed.Set(caller.String(), true)
}

func (a *Airdrop) hasAlreadyClaimed(caller std.Address) bool {
return a.alreadyClaimed.Has(caller.String())
}

func (a *Airdrop) isOnGoing() bool {
now := time.Now().Unix()
return (a.startTimestamp == 0 || a.startTimestamp <= now) &&
(a.endTimestamp == 0 || now < a.endTimestamp)
}

func (a *Airdrop) ToJSON() *json.Node {
return json.ObjectNode("", map[string]*json.Node{
"id": json.StringNode("", ufmt.Sprintf("%d", uint64(a.id))),
"tokenName": json.StringNode("", a.token.banker.GetName()),
"tokenSymbol": json.StringNode("", a.token.banker.GetSymbol()),
"amountPerAddr": json.StringNode("", strconv.FormatUint(a.amountPerAddr, 10)),
"startTimestamp": json.StringNode("", strconv.FormatInt(a.startTimestamp, 10)),
"endTimestamp": json.StringNode("", strconv.FormatInt(a.endTimestamp, 10)),
})
}

func mustGetAirdrop(airdropID uint64) *Airdrop {
id := seqid.ID(airdropID)
airdropRaw, exists := airdrops.Get(id.String())
Expand All @@ -120,12 +146,16 @@ func mustGetAirdrop(airdropID uint64) *Airdrop {
return airdropRaw.(*Airdrop)
}

func (a *Airdrop) hasAlreadyClaimed(caller std.Address) bool {
return a.alreadyClaimed.Has(caller.String())
}
func GetLastAirdropsJSON() string {
nodes := make([]*json.Node, 0, 10)
for i := int(nextAirdropID); i > int(nextAirdropID)-10; i-- {
airdropRaw, exists := airdrops.Get(seqid.ID(i).String())
if !exists {
continue
}

func (a *Airdrop) isOnGoing() bool {
now := time.Now().Unix()
return (a.startTimestamp == 0 || a.startTimestamp <= now) &&
(a.endTimestamp == 0 || now < a.endTimestamp)
airdrop := airdropRaw.(*Airdrop)
nodes = append(nodes, airdrop.ToJSON())
}
return json.ArrayNode("", nodes).String()
}
7 changes: 3 additions & 4 deletions gno/r/launchpad_grc20/render.gno
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,15 @@ func renderTokenPage(res *mux.ResponseWriter, req *mux.Request) {
res.Write("## Usage\n")
res.Write("You can create your own token by referring to the help section in the documentation and using the NewToken function.\nAfter creating your token, you can manage it easily through the provided interface.\nTo view details of any token created by this factory, simply visit the page ``:token/{name}``, replacing ``{name}`` with the token's name.\n")

if len(lastTokensIDcreated) > 0 {
if len(lastTokensCreated) > 0 {
res.Write("## Last tokens created\n")

for _, tokenIDs := range lastTokensIDcreated {
token := mustGetToken(tokenIDs)
for _, token := range lastTokensCreated {
res.Write(ufmt.Sprintf("### Name: %s - Symbol: %s\n", token.banker.GetName(), token.banker.GetSymbol()))
res.Write(ufmt.Sprintf("#### Total Supply: %d %s\n", token.banker.TotalSupply(), token.banker.GetSymbol()))
res.Write(ufmt.Sprintf("#### Decimals: %d\n", token.banker.GetDecimals()))
res.Write(ufmt.Sprintf("#### Admin: %s\n\n", token.admin.Owner().String()))
res.Write(ufmt.Sprintf("> Link: [:token/%s](launchpad_grc20:token/%s)\n\n", tokenIDs, tokenIDs))
res.Write(ufmt.Sprintf("> Link: [:token/%s](launchpad_grc20:token/%s)\n\n", token.banker.GetName(), token.banker.GetName()))
}
}
renderFooter(res, "")
Expand Down
55 changes: 45 additions & 10 deletions gno/r/launchpad_grc20/sale_grc20.gno
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package launchpad_grc20
import (
"encoding/hex"
"std"
"strconv"
"time"

"gno.land/p/demo/avl"
Expand All @@ -15,6 +16,7 @@ import (

type Sale struct {
token *Token
id seqid.ID
startTimestamp int64
endTimestamp int64
pricePerToken uint64
Expand Down Expand Up @@ -66,6 +68,10 @@ func NewSale(tokenName, merkleRoot string, startTimestamp, endTimestamp int64, p
panic("price per token must be greater than 0")
}

if limitPerAddr == 0 {
panic("limit per address must be greater than 0")
}

realmAddr := std.CurrentRealm().Addr()
if mintToken {
token.banker.Mint(realmAddr, maxGoal)
Expand All @@ -76,8 +82,11 @@ func NewSale(tokenName, merkleRoot string, startTimestamp, endTimestamp int64, p
}
}

saleID := nextSaleID.Next()

sale := Sale{
token: token,
id: saleID,
startTimestamp: startTimestamp,
endTimestamp: endTimestamp,
pricePerToken: pricePerToken,
Expand All @@ -90,7 +99,6 @@ func NewSale(tokenName, merkleRoot string, startTimestamp, endTimestamp int64, p
merkleRoot: merkleRoot,
}

saleID := nextSaleID.Next()
token.SalesIDs = append(token.SalesIDs, saleID)

sales.Set(saleID.String(), &sale)
Expand Down Expand Up @@ -157,15 +165,6 @@ func Finalize(saleID uint64) {
sale.finalized = true
}

func mustGetSale(saleID uint64) *Sale {
id := seqid.ID(saleID)
sale, exists := sales.Get(id.String())
if !exists {
panic("sale not found")
}
return sale.(*Sale)
}

func (s *Sale) isOnGoing() bool {
return s.startTimestamp <= time.Now().Unix() && (s.endTimestamp == 0 || time.Now().Unix() < s.endTimestamp)
}
Expand Down Expand Up @@ -267,3 +266,39 @@ func (s *Sale) payAllBuyers() {
return false
})
}

func (s *Sale) ToJSON() *json.Node {
return json.ObjectNode("", map[string]*json.Node{
"id": json.StringNode("", ufmt.Sprintf("%d", uint64(s.id))),
"tokenName": json.StringNode("", s.token.banker.GetName()),
"pricePerToken": json.StringNode("", strconv.FormatUint(s.pricePerToken, 10)),
"limitPerAddr": json.StringNode("", strconv.FormatUint(s.limitPerAddr, 10)),
"minGoal": json.StringNode("", strconv.FormatUint(s.minGoal, 10)),
"maxGoal": json.StringNode("", strconv.FormatUint(s.maxGoal, 10)),
"startTimestamp": json.StringNode("", strconv.FormatInt(s.startTimestamp, 10)),
"endTimestamp": json.StringNode("", strconv.FormatInt(s.endTimestamp, 10)),
})
}

func mustGetSale(saleID uint64) *Sale {
id := seqid.ID(saleID)
sale, exists := sales.Get(id.String())
if !exists {
panic("sale not found")
}
return sale.(*Sale)
}

func GetLastSalesJSON() string {
nodes := make([]*json.Node, 0, 10)
for i := int(nextSaleID); i > int(nextSaleID)-10; i-- {
saleRaw, exists := sales.Get(seqid.ID(i).String())
if !exists {
continue
}

sale := saleRaw.(*Sale)
nodes = append(nodes, sale.ToJSON())
}
return json.ArrayNode("", nodes).String()
}
41 changes: 33 additions & 8 deletions gno/r/launchpad_grc20/token_factory_grc20.gno
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ package launchpad_grc20

import (
"std"
"strconv"

"gno.land/p/demo/avl"
"gno.land/p/demo/grc/grc20"
"gno.land/p/demo/json"
"gno.land/p/demo/ownable"
"gno.land/p/demo/seqid"
)

const LENGTH_LAST_TOKENS_CACHE = 10

type Token struct {
banker *grc20.Banker
admin *ownable.Ownable
Expand All @@ -22,12 +26,11 @@ type Token struct {

var _ grc20.Token = (*Token)(nil)

var lastTokensIDcreated = []string{}

var (
tokens *avl.Tree // name -> token
factoryAdmin *ownable.Ownable
factoryVault std.Address
tokens *avl.Tree // name -> token
factoryAdmin *ownable.Ownable
factoryVault std.Address
lastTokensCreated = []*Token{}
)

// Initialize tori address as admin & vault for fees
Expand Down Expand Up @@ -75,10 +78,10 @@ func NewToken(name, symbol, image string, decimals uint, initialSupply, totalSup

tokens.Set(name, &inst)

if len(lastTokensIDcreated) == 5 {
lastTokensIDcreated = lastTokensIDcreated[:4]
if len(lastTokensCreated) == LENGTH_LAST_TOKENS_CACHE {
lastTokensCreated = lastTokensCreated[:(LENGTH_LAST_TOKENS_CACHE - 1)]
}
lastTokensIDcreated = append([]string{name}, lastTokensIDcreated...)
lastTokensCreated = append([]*Token{&inst}, lastTokensCreated...)
}

func Mint(name string, to std.Address, amount uint64) {
Expand Down Expand Up @@ -160,11 +163,33 @@ func (token Token) TransferFrom(from, to std.Address, amount uint64) error {
return token.Token().TransferFrom(from, to, amount)
}

func (token Token) ToJSON() *json.Node {
return json.ObjectNode("", map[string]*json.Node{
"name": json.StringNode("", token.banker.GetName()),
"symbol": json.StringNode("", token.banker.GetSymbol()),
"decimals": json.StringNode("", strconv.FormatUint(uint64(token.banker.GetDecimals()), 10)),
"admin": json.StringNode("", token.admin.Owner().String()),
"image": json.StringNode("", token.image),
"totalSupply": json.StringNode("", strconv.FormatInt(int64(token.TotalSupply()), 10)),
"totalSupplyCap": json.StringNode("", strconv.FormatInt(int64(token.totalSupplyCap), 10)),
"allowMint": json.BoolNode("", token.allowMint),
"allowBurn": json.BoolNode("", token.allowBurn),
})
}

func SetFactoryVault(vault std.Address) {
factoryAdmin.AssertCallerIsOwner()
factoryVault = vault
}

func GetLastTokensJSON() string {
nodes := make([]*json.Node, len(lastTokensCreated))
for i, token := range lastTokensCreated {
nodes[i] = token.ToJSON()
}
return json.ArrayNode("", nodes).String()
}

func mustGetToken(name string) *Token {
t, exists := tokens.Get(name)
if !exists {
Expand Down
27 changes: 27 additions & 0 deletions go/pkg/networks/features.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
FeatureTypeNFTBridge = FeatureType("NFTBridge")
FeatureTypeCosmWasmPremiumFeed = FeatureType("CosmWasmPremiumFeed")
FeatureTypeGnoProjectManager = FeatureType("GnoProjectManager")
FeatureTypeLaunchpadERC20 = FeatureType("LaunchpadERC20")
FeatureTypeNFTMarketplaceLeaderboard = FeatureType("NFTMarketplaceLeaderboard")
FeatureTypeCosmWasmNFTsBurner = FeatureType("CosmWasmNFTsBurner")
)
Expand Down Expand Up @@ -82,6 +83,26 @@ func (nb *NetworkBase) GetFeatureGnoProjectManager() (*FeatureGnoProjectManager,
return feature.(*FeatureGnoProjectManager), nil
}

type FeatureLaunchpadERC20 struct {
*FeatureBase
LaunchpadERC20PkgPath string `json:"launchpadERC20PkgPath"`
PaymentsDenom string `json:"paymentsDenom"`
}

var _ Feature = &FeatureLaunchpadERC20{}

func (f FeatureLaunchpadERC20) Type() FeatureType {
return FeatureTypeLaunchpadERC20
}

func (nb *NetworkBase) GetFeatureLaunchpadERC20() (*FeatureLaunchpadERC20, error) {
feature, err := nb.GetFeature(FeatureTypeLaunchpadERC20)
if err != nil {
return nil, err
}
return feature.(*FeatureLaunchpadERC20), nil
}

func UnmarshalFeature(b []byte) (Feature, error) {
var base FeatureBase
if err := json.Unmarshal(b, &base); err != nil {
Expand All @@ -106,6 +127,12 @@ func UnmarshalFeature(b []byte) (Feature, error) {
return nil, errors.Wrap(err, "failed to unmarshal feature GnoProjectManager")
}
return &f, nil
case FeatureTypeLaunchpadERC20:
var f FeatureLaunchpadERC20
if err := json.Unmarshal(b, &f); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal feature LaunchpadERC20")
}
return &f, nil
}
return nil, errors.Errorf("unknown feature type %s", base.Type)
}
Loading
Loading