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: r/demo/foo20airdrop - Merkle Airdrop contract example #906

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

albttx
Copy link
Member

@albttx albttx commented Jun 16, 2023

Description

This PR bring an example for a merkle airdrop contract.

  • the package p/demo/airdrop
  • the realm r/demo/foo20airdrop

How it's works ?

A merkle airdrop contract works by saving off-chain the elements of the merkle tree. ONLY the Merkle root is saved on the realm.

To confirm an element is present, we just need to send to the contract a merkle proof.

@albttx albttx requested review from jaekwon, moul and a team as code owners June 16, 2023 13:00
@albttx albttx self-assigned this Jun 16, 2023
@albttx albttx marked this pull request as draft June 16, 2023 13:01
@github-actions github-actions bot added 📦 🤖 gnovm Issues or PRs gnovm related 🧾 package/realm Tag used for new Realms or Packages. labels Jun 16, 2023
@albttx
Copy link
Member Author

albttx commented Jun 16, 2023

waiting for: #893 and #895 to undraft

@albttx albttx force-pushed the r/foo20-airdrop branch 2 times, most recently from 2060eff to 2675ea9 Compare July 23, 2023 12:42
@github-actions github-actions bot removed the 📦 🤖 gnovm Issues or PRs gnovm related label Jul 23, 2023
@albttx albttx changed the title r/demo/foo20airdrop - Merkle Airdrop contract example feat: r/demo/foo20airdrop - Merkle Airdrop contract example Jul 23, 2023
@albttx albttx marked this pull request as ready for review July 26, 2023 15:18

func TestClaimAirdrop(t *testing.T) {
contractAddr := std.DerivePkgAddr("gno.land/r/demo/foo20-airdrop")
std.TestSetOrigCaller(contractAddr)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you still need that ?

p/demo/foo20 uses std.PrevRealm() now right ?

"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't work yet

@@ -0,0 +1,88 @@
package airdrop
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p/demo/airdrop seems to be too generic IMO, so I would either name it accurately like p/demo/grc20_merkle_airdrop or use a subpaths, maybe p/demo/airdrop/grc20_merkle.

type AirdropData struct {
Address std.Address
// TODO: use std.Coin
Amount uint64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For better control and data integrity, keep the fields in the Airdrop struct unexported.

To maintain easy marshaling with the Bytes helper, consider this approach:

type Airdrop struct {
    data struct {
        Address std.Address
        Amount  uint64
    }
}

Copy link
Member

@zivkovicmilos zivkovicmilos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 💯

Please see @moul's comments, otherwise we should be good to go

Comment on lines +82 to +93
ma.claimed.Iterate("", "", func(k string, v interface{}) bool {
claimed += v.(uint64)
return false
})

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, do you forsee this method being called often? If not we can leave the iteration, otherwise we might want to consider keeping a claimed counter in MerkleAirdrop

proofs, err := tree.Proof(leaf)
if err != nil {
t.Fatalf("failed to generate proof, %v", err)
return
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant return here

var (
token grc20.IGRC20 = foo20.GRC20()

// admin std.Address = "g1sw5xklxjjuv0yvuxy5f5s3l3mnj0nqq626a9wr" // albttx.gno
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover?

Comment on lines 26 to 44
err := foo20airdrop.Claim(data, proofs)
if err != nil {
panic(err.Error())
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: you can inline this

}

// for tests purpose
func reset() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't you modify foo20airdrop from the test directly, since they are in the same package? You can then drop this method entirely

},
}

func TestRegisterMerkle(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about completely removing this test?
You verify it works in TestClaimAirdrop regardless (happy path)

// instantiate foo20 airdrop contract
tree := merkle.NewTree(leaves)
RegisterMerkleRoot(tree.Root())
defer reset()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the need for a defer (reset at all)?

Comment on lines +61 to +67
ttClaimed := TotalClaimed()
if ttClaimed != sumClaimed {
t.Fatalf("expected: %d", sumClaimed)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: you can inline this

proofs, err := tree.Proof(leaf)
if err != nil {
t.Fatalf("failed to generate proof, %v", err)
return
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant return

"gno.land/r/demo/users"
)

var leaves []merkle.Hashable = []airdrop.AirdropData{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about moving this to TestClaimAirdrop? (see my next comment about removing TestRegisterMerkle)

Copy link
Member

@moul moul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just blocking since there are several changes. Let’s make an additional round of reviews.

@albttx
Copy link
Member Author

albttx commented Aug 9, 2023

There is tests issue once rebased with master.

There is a situation to figure out, with grc20.IGRC20, because it return a grc20.UserToken .

When user1.gno -> r/foo20-airdrop get foo20.GRC20() and then from r/foo20-airdrop exec foo20.GRC20().Transfert, std.PrevRealm isn't the realm but the user ...

Possible fix could be to update in user_token.gno to use CurrentRealm rather than PrevRealm

@moul
Copy link
Member

moul commented Aug 9, 2023

Related (and depending?) on #952

@zivkovicmilos
Copy link
Member

Hey @albttx,

What's the status of this PR?

@moul moul added this to the 🌟 main.gno.land (wanted) milestone Sep 8, 2023
@github-actions github-actions bot added the 📦 🤖 gnovm Issues or PRs gnovm related label Oct 18, 2023
@codecov
Copy link

codecov bot commented Oct 18, 2023

Codecov Report

Attention: 21 lines in your changes are missing coverage. Please review.

Comparison is base (89428c5) 47.84% compared to head (9cf2f47) 47.54%.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #906      +/-   ##
==========================================
- Coverage   47.84%   47.54%   -0.31%     
==========================================
  Files         369      367       -2     
  Lines       62764    62307     -457     
==========================================
- Hits        30028    29622     -406     
+ Misses      30308    30265      -43     
+ Partials     2428     2420       -8     
Files Coverage Δ
gnovm/pkg/gnolang/ownership.go 6.93% <0.00%> (-0.05%) ⬇️
gnovm/pkg/gnolang/realm.go 1.42% <60.00%> (+0.43%) ⬆️
gnovm/pkg/gnolang/machine.go 39.15% <0.00%> (-0.45%) ⬇️

... and 27 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
📦 🤖 gnovm Issues or PRs gnovm related 🧾 package/realm Tag used for new Realms or Packages.
Projects
Status: 🌟 Wanted for Launch
Development

Successfully merging this pull request may close these issues.

5 participants