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

GSW-1142 feat: gns (mint with permission) + pre-calculated halving amount #247

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
95 changes: 95 additions & 0 deletions _deploy/r/demo/gnoswap/consts_halving/consts.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package consts

import (
"std"
)

// GNOSWAP SERVICE
const (
GNOSWAP_ADMIN std.Address = "g13f63ua8uhmuf9mgc0x8zfz04yrsaqh7j78vcgq" // GSA
FEE_COLLECTOR std.Address = "g18sp3hq6zqfxw88ffgz773gvaqgzjhxy62l9906" // FCL

INTERNAL_REWARD_ACCOUNT std.Address = "g1jms5fx2raq4qfkq3502mfh25g54nyl5qeuvz5y" // IRA for GNS
BLOCK_GENERATION_INTERVAL int64 = 5 // 5 seconds
)

// WRAP & UNWRAP
const (
GNOT string = "gnot"
WRAPPED_WUGNOT string = "gno.land/r/demo/wugnot"

UGNOT_MINT_DEPOSIT_TO_WRAP uint64 = 1000 // defined in gno.land/r/demo/wugnot
)

// CONTRACT PATH & ADDRESS
var (
POOL_PATH string = "gno.land/r/demo/pool"
POOL_ADDR std.Address = std.DerivePkgAddr(POOL_PATH) // g15z32w7txv6lw259xzhzzmwtwmcjjc0m6dqzh6f

POSITION_PATH string = "gno.land/r/demo/position"
POSITION_ADDR std.Address = std.DerivePkgAddr(POSITION_PATH) // g10wwa53xgu4397kvzz7akxar9370zjdpwux5th9

STAKER_PATH string = "gno.land/r/demo/staker"
STAKER_ADDR std.Address = std.DerivePkgAddr(STAKER_PATH) // g1puv9dz470prjshjm9qyg25dyfvrgph2kvjph68

ROUTER_PATH string = "gno.land/r/demo/router"
ROUTER_ADDR std.Address = std.DerivePkgAddr(ROUTER_PATH) // g1pjtpgjpsn4hjfv2n4mpz8cczdn32jkpsqwxuav

GOV_PATH string = "gno.land/r/demo/gov"
GOV_ADDR std.Address = std.DerivePkgAddr(GOV_PATH) // g1kmat25auuqf0h5qvd4q7s707r8let5sky4tr76

GNS_PATH string = "gno.land/r/demo/gns"
GNS_ADDR std.Address = std.DerivePkgAddr(GNS_PATH) // g1zs77uvf8mxzq5k6lu2g8l8fzm6fvf79zkp6cgg

GNFT_PATH string = "gno.land/r/demo/gnft"
GNFT_ADDR std.Address = std.DerivePkgAddr(GNFT_PATH) // g1mpsh77gemyy7ku2hu40c4t4w0ntegp4rg6m4cr

WUGNOT_PATH string = "gno.land/r/demo/wugnot"
WUGNOT_ADDR std.Address = std.DerivePkgAddr(WUGNOT_PATH) // g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6

EMISSION_PATH string = "gno.land/r/demo/emission"
EMISSION_ADDR std.Address = std.DerivePkgAddr(EMISSION_PATH) // g1znut3752hsmu227rat7zajkc2mswdjf08egtqu
)

// NUMBER
const (
// calculated by https://mathiasbynens.be/demo/integer-range
MAX_UINT8 string = "255"
UINT8_MAX uint8 = 255

MAX_UINT16 string = "65535"
UINT16_MAX uint16 = 65535

MAX_UINT32 string = "4294967295"
UINT32_MAX uint32 = 4294967295

MAX_UINT64 string = "18446744073709551615"
UINT64_MAX uint64 = 18446744073709551615

MAX_UINT128 string = "340282366920938463463374607431768211455"

MAX_UINT160 string = "1461501637330902918203684832716283019655932542975"

MAX_UINT256 string = "115792089237316195423570985008687907853269984665640564039457584007913129639935"

// Tick Related
MIN_TICK int32 = -887272
MAX_TICK int32 = 887272

MIN_SQRT_RATIO string = "4295128739" // same as TickMathGetSqrtRatioAtTick(MIN_TICK)
MAX_SQRT_RATIO string = "1461446703485210103287273052203988822378723970342" // same as TickMathGetSqrtRatioAtTick(MAX_TICK)

MIN_PRICE string = "4295128740" // MIN_SQRT_RATIO + 1
MAX_PRICE string = "1461446703485210103287273052203988822378723970341" // MAX_SQRT_RATIO - 1

// ETC
Q64 string = "18446744073709551616" // 2 ** 64
Q96 string = "79228162514264337593543950336" // 2 ** 96
Q128 string = "340282366920938463463374607431768211456" // 2 ** 128

)

// ETCs
const (
ZERO_ADDRESS std.Address = ""
)
1 change: 1 addition & 0 deletions _deploy/r/demo/gnoswap/consts_halving/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module gno.land/r/demo/gnoswap/consts
9 changes: 9 additions & 0 deletions _deploy/r/demo/gns_halving/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module gno.land/r/demo/gns

require (
gno.land/p/demo/grc/grc20 v0.0.0-latest
gno.land/p/demo/ufmt v0.0.0-latest
gno.land/p/demo/users v0.0.0-latest
gno.land/r/demo/users v0.0.0-latest
gno.land/r/demo/gnoswap/consts v0.0.0-latest
)
122 changes: 122 additions & 0 deletions _deploy/r/demo/gns_halving/gns.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package gns

import (
"std"
"strings"
"time"

"gno.land/p/demo/grc/grc20"
"gno.land/p/demo/ufmt"
"gno.land/r/demo/users"

pusers "gno.land/p/demo/users"

"gno.land/r/demo/gnoswap/consts"
)

const MAXIMUM_SUPPLY = uint64(1_000_000_000_000_000) // 1B

var (
deployedHeight int64
deployedAt time.Time
lastMintedHeight int64
amountToEmission uint64
)

var (
gns *grc20.AdminToken
)

func init() {
gns = grc20.NewAdminToken("Gnoswap", "GNS", 6)
gns.Mint(consts.GNOSWAP_ADMIN, 100_000_000_000_000) // 100_000_000 GNS ≈ 0.1B

amountToEmission = MAXIMUM_SUPPLY - uint64(100_000_000_000_000)

height := std.GetHeight()
deployedHeight = height
deployedAt = time.Now()
lastMintedHeight = 0
}

func TotalSupply() uint64 {
return gns.TotalSupply()
}

func BalanceOf(owner pusers.AddressOrName) uint64 {
balance, err := gns.BalanceOf(users.Resolve(owner))
if err != nil {
panic(err.Error())
}
return balance
}

func Allowance(owner, spender pusers.AddressOrName) uint64 {
allowance, err := gns.Allowance(users.Resolve(owner), users.Resolve(spender))
if err != nil {
panic(err.Error())
}
return allowance
}

func Transfer(to pusers.AddressOrName, amount uint64) {
caller := std.PrevRealm().Addr()
err := gns.Transfer(caller, users.Resolve(to), amount)
if err != nil {
panic(err.Error())
}
}

func Approve(spender pusers.AddressOrName, amount uint64) {
caller := std.PrevRealm().Addr()
err := gns.Approve(caller, users.Resolve(spender), amount)
if err != nil {
panic(err.Error())
}
}

func TransferFrom(from, to pusers.AddressOrName, amount uint64) {
caller := std.PrevRealm().Addr()
err := gns.TransferFrom(caller, users.Resolve(from), users.Resolve(to), amount)
if err != nil {
panic(err.Error())
}
}

func Render(path string) string {
parts := strings.Split(path, "/")
c := len(parts)

switch {
case path == "":
return gns.RenderHome()
case c == 2 && parts[0] == "balance":
owner := pusers.AddressOrName(parts[1])
balance, _ := gns.BalanceOf(users.Resolve(owner))
return ufmt.Sprintf("%d\n", balance)
default:
return "404\n"
}
}

// Mint
func Mint(address pusers.AddressOrName) {
// only emission contract can call Mint
caller := std.PrevRealm().Addr()
if caller != consts.EMISSION_ADDR {
panic("only emission contract can call Mint")
}

nowHeight := std.GetHeight()
for i := lastMintedHeight + 1; i <= nowHeight; i++ {
amount := getAmountByHeight(i)
err := gns.Mint(users.Resolve(address), amount)
if err != nil {
panic(err.Error())
}
lastMintedHeight = i

// debug
// println("height:", i, "minted:", amount)
}
}
69 changes: 69 additions & 0 deletions _deploy/r/demo/gns_halving/gns_test.gnoA
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package gns

import (
"std"
"testing"

"gno.land/p/demo/testutils"
pusers "gno.land/p/demo/users"

"gno.land/r/demo/gnoswap/consts"
)

func TestInitValues(t *testing.T) {
shouldEQ(t, deployedHeight, 123)
shouldEQ(t, int64(deployedAt.Unix()), 1234567890)
shouldEQ(t, lastMintedHeight, 0)
}

func TestMint(t *testing.T) {
emissionUsers := pusers.AddressOrName(consts.EMISSION_ADDR)
emissionRealm := std.NewCodeRealm(consts.EMISSION_PATH)
std.TestSetRealm(emissionRealm)

shouldEQ(t, TotalSupply(), 100_000_000_000_000)

Mint(emissionUsers) // + 4_387_842_345 (block 1 ~ 123)
shouldEQ(t, TotalSupply(), 100_000_000_000_000+4_387_842_345)

Mint(emissionUsers) // no block mined => no emission
shouldEQ(t, TotalSupply(), 100_000_000_000_000+4_387_842_345)

std.TestSkipHeights(1)
Mint(emissionUsers) // + 35_673_515 (block 124)
shouldEQ(t, TotalSupply(), 100_000_000_000_000+4_387_842_345+35_673_515)
}

func TestMintNoPermission(t *testing.T) {
dummyAddr := testutils.TestAddress("dummy")
dummyUser := pusers.AddressOrName(dummyAddr)
dummyRealm := std.NewUserRealm(dummyAddr)
std.TestSetRealm(dummyRealm)

shouldPanicWithMsg(
t,
func() {
Mint(dummyUser)
},
"only emission contract can call Mint",
)
}

func shouldEQ(t *testing.T, got, expected interface{}) {
if got != expected {
t.Errorf("got %v, expected %v", got, expected)
}
}

func shouldPanicWithMsg(t *testing.T, f func(), msg string) {
defer func() {
if r := recover(); r == nil {
t.Errorf("The code did not panic")
} else {
if r != msg {
t.Errorf("excepted panic(%v), got(%v)", msg, r)
}
}
}()
f()
}
Loading