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-1069 fix: one click staking for native ugnot coin (wrapping issue) #218

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
11 changes: 11 additions & 0 deletions staker/_TEST_/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ var (
)

/* HELPER */
func ugnotBalanceOf(addr std.Address) uint64 {
testBanker := std.GetBanker(std.BankerTypeRealmIssue)

coins := testBanker.GetCoins(addr)
if len(coins) == 0 {
return 0
}

return uint64(testBanker.GetCoins(addr)[0].Amount)
}

func shouldEQ(t *testing.T, got, expected interface{}) {
if got != expected {
t.Errorf("got %v, expected %v", got, expected)
Expand Down
92 changes: 0 additions & 92 deletions staker/_TEST_/_TEST_staker_mint_and_stake_test.gn

This file was deleted.

156 changes: 156 additions & 0 deletions staker/_TEST_/_TEST_staker_mint_and_stake_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package staker

import (
"std"
"testing"

pl "gno.land/r/demo/pool"

"gno.land/r/demo/bar"
"gno.land/r/demo/gns"
"gno.land/r/demo/qux"
"gno.land/r/demo/wugnot"

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

func init() {
// init pool tiers
// tier 1
poolTiers["gno.land/r/demo/bar:gno.land/r/demo/qux:500"] = 1 // DEV

// tier 2
poolTiers["GNS/USDT_500"] = 2
poolTiers["ATOM/GNS_500"] = 2

// tier 3
poolTiers["ATOM/GNOT_500"] = 3
poolTiers["ATOM/USDT_500"] = 3
poolTiers["ATOM/WETH_500"] = 3
}

func TestPoolInitCreatePool(t *testing.T) {
std.TestSetPrevAddr(gsa)

gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE)
std.TestSkipHeights(1)

pl.CreatePool(barPath, quxPath, 500, "130621891405341611593710811006") // tick 10_000 ≈ x2.7
// --- event: {GNOSWAP gno.land/r/demo/pool CreatePool [{m_origCaller g13f63ua8uhmuf9mgc0x8zfz04yrsaqh7j78vcgq} {m_prevRealm } {p_poolPath gno.land/r/demo/bar:gno.land/r/demo/qux:500}]}

pl.CreatePool(consts.GNOT, consts.GNS_PATH, 500, "130621891405341611593710811006") // tick 10_000 ≈ x2.7
// --- event: {GNOSWAP gno.land/r/demo/pool CreatePool [{m_origCaller g13f63ua8uhmuf9mgc0x8zfz04yrsaqh7j78vcgq} {m_prevRealm } {p_poolPath gno.land/r/demo/gns:gno.land/r/demo/wugnot:500}]}

std.TestSkipHeights(1)
}

func TestMintAndStakeGRC20Pair(t *testing.T) {
std.TestSetPrevAddr(gsa)
bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX)
qux.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX)
std.TestSkipHeights(2)

lpTokenId, liquidity, amount0, amount1, poolPath := MintAndStake(
barPath, // token0
quxPath, // token1
fee500, // fee
int32(9000), // tickLower
int32(11000), // tickUpper
"1000", // amount0Desired
"1000", // amount1Desired
"1", // amount0Min
"1", // amount1Min
max_timeout,
)
// event: {GNOSWAP gno.land/r/demo/position Mint [{m_origCaller g13f63ua8uhmuf9mgc0x8zfz04yrsaqh7j78vcgq} {m_prevRealm gno.land/r/demo/staker} {p_poolPath gno.land/r/demo/bar:gno.land/r/demo/qux:500} {p_tickLower 9000} {p_tickUpper 11000} {tokenId 1} {liquidity 12437} {amount0 368} {amount1 1000}]}
// event: {GNOSWAP gno.land/r/demo/staker StakeToken [{p_tokenId 1} {poolPath gno.land/r/demo/bar:gno.land/r/demo/qux:500} {amount0 368} {amount1 1000}]}
shouldEQ(t, lpTokenId, uint64(1))

std.TestSkipHeights(1)
}

func TestMintAndStakeNative(t *testing.T) {
std.TestSetPrevAddr(gsa)
gns.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX)
wugnot.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX)
wugnot.Approve(a2u(consts.POSITION_ADDR), consts.UINT64_MAX)
std.TestSkipHeights(2)

// prepare 100005ugnot (5 for refund test)
testBanker := std.GetBanker(std.BankerTypeRealmIssue)
testBanker.IssueCoin(gsa, "ugnot", 100005)

// simulate transfer & decrase
gsaNativeBalance := ugnotBalanceOf(gsa)
shouldEQ(t, gsaNativeBalance, 100005)

std.TestSetOrigSend(std.Coins{{"ugnot", 100005}}, nil)
testBanker.RemoveCoin(std.GetOrigCaller(), "ugnot", -100005)

gsaNativeBalance = ugnotBalanceOf(gsa)
shouldEQ(t, gsaNativeBalance, 0)

gsaOldWugnotBalance := wugnot.BalanceOf(a2u(gsa))
shouldEQ(t, gsaOldWugnotBalance, 0)

lpTokenId, liquidity, amount0, amount1, poolPath := MintAndStake(
consts.GNOT, // token0
consts.GNS_PATH, // token1
fee500, // fee
int32(9000), // tickLower
int32(11000), // tickUpper
"100000", // amount0Desired
"100000", // amount1Desired
"1", // amount0Min
"1", // amount1Min
max_timeout,
)
// event: {GNOSWAP gno.land/r/demo/position Mint [{m_origCaller g13f63ua8uhmuf9mgc0x8zfz04yrsaqh7j78vcgq} {m_prevRealm gno.land/r/demo/staker} {p_poolPath gno.land/r/demo/gns:gno.land/r/demo/wugnot:500} {p_tickLower -11000} {p_tickUpper -9000} {tokenId 2} {liquidity 1243732} {amount0 100000} {amount1 36790}]}
// event: {GNOSWAP gno.land/r/demo/staker StakeToken [{p_tokenId 2} {poolPath gno.land/r/demo/gns:gno.land/r/demo/wugnot:500} {amount0 100000} {amount1 36790}]}

shouldEQ(t, lpTokenId, uint64(2))
std.TestSkipHeights(1)

// SPEND ALL WUGNOT
newOldWugnotBalance := wugnot.BalanceOf(a2u(gsa))
shouldEQ(t, gsaOldWugnotBalance, 0)

gsaNativeBalance = ugnotBalanceOf(gsa)
shouldEQ(t, gsaNativeBalance, 63215)
// 1. 100005 ugnot sent
// 2. 100005 ugnot wrapped to wugnot
// 3. 36790 wugnot spent to mint (amount1)
// 4. refund 100005 - 36790 = 63215

}

/*
func TestPositionCollectFee(t *testing.T) {
std.TestSetPrevAddr(gsa)
pn.CollectFee(1) // lpTokenId
std.TestSkipHeights(1)
}

func TestCollectReward(t *testing.T) {
// internal reward distribution
std.TestSetPrevAddr(consts.INTERNAL_REWARD_ACCOUNT)
gns.Approve(a2u(consts.STAKER_ADDR), consts.UINT64_MAX)

std.TestSetPrevAddr(gsa)
CollectReward(1) // lpTokenId
std.TestSkipHeights(1)
}

func TestUnstakeToken(t *testing.T) {
ownerOfLp1 := gnft.OwnerOf(tid(1))
shouldEQ(t, ownerOfLp1, a2u(consts.STAKER_ADDR))

std.TestSetPrevAddr(gsa)
UnstakeToken(1) // lpTokenId
std.TestSkipHeights(1)

ownerOfLp1 = gnft.OwnerOf(tid(1))
shouldEQ(t, ownerOfLp1, a2u(gsa))
}

*/
21 changes: 21 additions & 0 deletions staker/mint_stake.gno
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package staker

import (
"std"

pn "gno.land/r/demo/position"

"gno.land/p/demo/ufmt"

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

Expand All @@ -20,6 +24,23 @@ func MintAndStake(
amount1Min string, // *u256.Uint
deadline int64,
) (uint64, string, string, string, string) { // tokenId, liquidity, amount0, amount1, poolPath ( *u256.Uint x3)

// if one click native
if token0 == consts.GNOT || token1 == consts.GNOT {
// check sent ugnot
sent := std.GetOrigSend()
ugnotSent := uint64(sent.AmountOf("ugnot"))

// not enough ugnot sent
if ugnotSent < consts.UGNOT_MINT_DEPOSIT_TO_WRAP {
panic(ufmt.Sprintf("[STAKER] mint_stake.gno__MintAndStake() || too less(%d) ugnot sent (minimum:%d)", ugnotSent, consts.UGNOT_MINT_DEPOSIT_TO_WRAP))
}

// send it over to position to wrap
banker := std.GetBanker(std.BankerTypeRealmSend)
banker.SendCoins(consts.STAKER_ADDR, consts.POSITION_ADDR, std.Coins{{"ugnot", int64(ugnotSent)}})
}

tokenId, liquidity, amount0, amount1 := pn.Mint(
token0,
token1,
Expand Down
10 changes: 10 additions & 0 deletions staker/utils.gno
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ func uint64ToStr(i uint64) string {
return strconv.FormatInt(int64(i), 10)
}

func strToUint64(s string) uint64 {
i, err := strconv.Atoi(s)

if err != nil {
panic(ufmt.Sprintf("[STAKER] utils.gno__strToUint64() || failed to convert string(%s) to uint64", s))
}

return uint64(i)
}

func boolToStr(b bool) string {
if b {
return "true"
Expand Down
Loading