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): realms & pkg #1263

Merged
merged 48 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
7cbc33a
feat(erc20-launchpad): initialize token factory realm
MikaelVallenet Aug 24, 2024
a933f60
feat(erc20-launchpad): initialize gno mod
MikaelVallenet Aug 24, 2024
193c416
feat(erc20-launchpad): add totalSupplyCap, allowMint and allowBurn to…
MikaelVallenet Aug 24, 2024
22a11a5
feat: add 2.5% fee at creation of grc20 token
MikaelVallenet Aug 30, 2024
f9f8387
feat: add airdrop contract
MikaelVallenet Sep 2, 2024
3e992c4
feat(launchpad-grc20): add redeem function in airdrop contract
MikaelVallenet Sep 2, 2024
dcb5597
fix(launchpad-grc20): resolve syntax errors raised by gnovm
MikaelVallenet Sep 2, 2024
5a94ec1
fix(launchpad-grc20): resolve syntax errors raised by gnovm
MikaelVallenet Sep 2, 2024
ac8b2b9
feat(launchpad-grc20): add render in a separate file and set a welcom…
MikaelVallenet Sep 2, 2024
199b485
chore(launchpad-grc20): gofumpt
MikaelVallenet Sep 3, 2024
44e9324
feat(launchpad-grc20): add mux router and define the render routes st…
MikaelVallenet Sep 3, 2024
8dcf122
feat(launchpad-grc20): add rendering of token details
MikaelVallenet Sep 3, 2024
012380f
feat(launchpad-grc20): add rendering of tokens balance for each user
MikaelVallenet Sep 3, 2024
924e1f2
feat(launchpad-grc20): add redeem test of airdrop
MikaelVallenet Sep 4, 2024
70edde2
chore(launchpad-grc20): run gofumpt
MikaelVallenet Sep 4, 2024
e71cdb5
feat(launchpad-grc20): add render of airdrop details & claim check page
MikaelVallenet Sep 4, 2024
e2ba892
feat(launchpad-grc20): add start & end date for airdrop
MikaelVallenet Sep 5, 2024
84dbfba
fix(launchpad-grc20): save timestamp end & start into the airdrop str…
MikaelVallenet Sep 5, 2024
a4c6205
feat(launchpad-grc20): add sale realm w/ creating and buying mechanism
MikaelVallenet Sep 5, 2024
dbfeb12
feat(launchpad-grc20): add sale render functions
MikaelVallenet Sep 5, 2024
8556305
tests(launchpad-grc20): add airdrop tests
MikaelVallenet Sep 6, 2024
f9bc582
tests(launchpad-grc20): add new token tests
MikaelVallenet Sep 6, 2024
2012e77
tests(launchpad-grc20): add mint token tests
MikaelVallenet Sep 6, 2024
e952442
tests(launchpad-grc20): add burn token tests
MikaelVallenet Sep 6, 2024
19c583e
feat(launchpad-grc20): add buy function
MikaelVallenet Sep 7, 2024
c3b2850
feat(launchpad-grc20): add refund mechanism for sale when not reachin…
MikaelVallenet Sep 7, 2024
7cc7c7c
fix(launchpad-grc20): fix sales syntax errors
MikaelVallenet Sep 7, 2024
965beae
tests(launchpad-grc20): add sale creation test
MikaelVallenet Sep 7, 2024
f7beaf8
tests(launchpad-grc20): add sale buy & finalize test
MikaelVallenet Sep 8, 2024
8a1141e
feat(launchpad-grc20): add ownable factory admin that can edit factor…
MikaelVallenet Sep 9, 2024
e8c566a
feat(launchpad-grc20): add optional merkle tree whitelist in sale
MikaelVallenet Sep 9, 2024
9aef4ea
tests(launchpad-grc20): add private sale test creation & buy mechanism
MikaelVallenet Sep 9, 2024
7214653
chore(launchpad-grc20): run gofumpt & fix lint errors
MikaelVallenet Sep 9, 2024
2caa3c4
tests(launchpad-grc20): implement interface grc20.Token on our token …
MikaelVallenet Sep 9, 2024
5f3a2a9
tests(launchpad-grc20): implement interface grc20.Token on our token …
MikaelVallenet Sep 9, 2024
5b1679c
chore(launchpad-grc20): run gno mod tidy
MikaelVallenet Sep 9, 2024
c41c57c
style(launchpad-grc20): add a page to display balance of a buyer for …
MikaelVallenet Sep 9, 2024
4e3a497
feat(launchpad-grc20): add ClaimJSON function to pass the proofs thro…
MikaelVallenet Sep 10, 2024
1466afb
feat(launchpad-grc20): add BuyJSON function to pass the proofs throug…
MikaelVallenet Sep 10, 2024
ddee6f5
fix(launchpad-grc20): add json & hex imports on sale contract
MikaelVallenet Sep 10, 2024
7fab696
feat(launchpad-grc20): add render of 5 last tokens, airdrop & sale cr…
MikaelVallenet Sep 10, 2024
916cf9c
feat(launchpad-grc20): add render of airdrops & sales linked to a tok…
MikaelVallenet Sep 10, 2024
fa03e3e
feat(launchpad-grc20): use seqid instead of basic uint64
MikaelVallenet Sep 10, 2024
a1349fc
feat(launchpad-grc20): use gnoland/p/demo/merkle pkg & fix seqid display
MikaelVallenet Sep 11, 2024
b96c8cf
feat(launchpad-grc20): use a modified verision of merkle tree pkg
MikaelVallenet Sep 11, 2024
334bc5d
fix(launchpad-grc20): initialize the sales & airdrop seqid at 0
MikaelVallenet Sep 11, 2024
3833126
fix(p/demo/merkle): use constructor & position getter
MikaelVallenet Sep 12, 2024
1cfce78
ci(launchpad-grc20): bump gno hash commit
MikaelVallenet Sep 12, 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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ start.gnodev-e2e:
.PHONY: clone-gno
clone-gno:
mkdir -p gnobuild
cd gnobuild && git clone https://github.com/gnolang/gno.git && cd gno && git checkout 9b114172063feaf2da4ae7ebb8263cada3ba699b
cd gnobuild && git clone https://github.com/gnolang/gno.git && cd gno && git checkout 8f800ece85a765113dfa4924da1c06f56865460c
cp -r ./gno/p ./gnobuild/gno/examples/gno.land/p/teritori

.PHONY: build-gno
Expand Down
8 changes: 8 additions & 0 deletions gno/p/jsonutil/jsonutil.gno
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ func MustUint64(value *json.Node) uint64 {
return uint64(MustInt(value)) // FIXME: full uint64 range support (currently limited to [-2^63, 2^63-1])
}

func Uint8Node(value uint8) *json.Node {
return json.StringNode("", strconv.FormatUint(uint64(value), 10))
}

func MustUint8(value *json.Node) uint8 {
return uint8(MustInt(value))
}

func AVLTreeNode(root *avl.Tree, transform func(elem interface{}) *json.Node) *json.Node {
if root == nil {
return EmptyObjectNode()
Expand Down
131 changes: 131 additions & 0 deletions gno/r/launchpad_grc20/airdrop_grc20.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package launchpad_grc20

import (
"encoding/hex"
"std"
"time"

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

type Airdrop struct {
token *Token
merkleRoot string
startTimestamp int64
endTimestamp int64
amountPerAddr uint64
alreadyClaimed *avl.Tree
}

var (
airdrops *avl.Tree // airdrop ID -> airdrop
nextAirdropID seqid.ID
)

func init() {
airdrops = avl.NewTree()
nextAirdropID = seqid.ID(0)
}

func NewAirdrop(tokenName, merkleRoot string, amountPerAddr uint64, startTimestamp, endTimestamp int64) uint64 {
token := mustGetToken(tokenName)
token.admin.AssertCallerIsOwner()

if !token.allowMint {
panic("token is not mintable")
}

now := time.Now().Unix()
if startTimestamp != 0 && startTimestamp < now {
panic("invalid start timestamp, must be in the future or be equal to 0 to start immediately")
}

if endTimestamp != 0 && endTimestamp < now {
panic("invalid end timestamp, must be in the future or be equal to 0 to never end")
}

if endTimestamp != 0 && startTimestamp >= endTimestamp {
panic("invalid timestamps, start must be before end")
}

airdrop := Airdrop{
token: token,
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)

return uint64(airdropID)
}

func ClaimJSON(airdropID uint64, proofsJSON string) {
nodes, err := json.Unmarshal([]byte(proofsJSON))
if err != nil {
panic("invalid json proofs")
}
vals := nodes.MustArray()
proofs := make([]merkle.Node, 0, len(vals))
for _, val := range vals {
obj := val.MustObject()
data, err := hex.DecodeString(obj["hash"].MustString())
if err != nil {
panic("invalid hex encoded hash")
}
node := merkle.NewNode(data, jsonutil.MustUint8(obj["pos"]))
proofs = append(proofs, node)
}
Claim(airdropID, proofs)
}

func Claim(airdropID uint64, proofs []merkle.Node) {
airdrop := mustGetAirdrop(airdropID)
caller := std.PrevRealm().Addr()

if !airdrop.isOnGoing() {
panic("airdrop is not ongoing, look at the airdrop period")
}

if airdrop.hasAlreadyClaimed(caller) {
panic("already claimed")
}

leaf := Leaf{[]byte(caller.String())}
if !merkle.Verify(airdrop.merkleRoot, leaf, proofs) {
panic("invalid proof")
}

airdrop.token.banker.Mint(caller, airdrop.amountPerAddr)

airdrop.alreadyClaimed.Set(caller.String(), true)
}

func mustGetAirdrop(airdropID uint64) *Airdrop {
id := seqid.ID(airdropID)
airdropRaw, exists := airdrops.Get(id.String())
if !exists {
panic("airdrop not found")
}

return airdropRaw.(*Airdrop)
}

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)
}
Loading
Loading