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-1968 refactor: commonly used functions #444

Merged
merged 7 commits into from
Dec 20, 2024
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
29 changes: 29 additions & 0 deletions _deploy/r/gnoswap/common/address_and_username.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package common

import (
"std"

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

// AddrToUser converts a type from address to AddressOrName.
// It panics if the address is invalid.
func AddrToUser(addr std.Address) pusers.AddressOrName {
assertValidAddr(addr)
return pusers.AddressOrName(addr)
}

// UserToAddr converts a type from AddressOrName to address.
// by resolving the user through the users realms.
func UserToAddr(user pusers.AddressOrName) std.Address {
return users.Resolve(user)
}

// assertValidAddr checks if the given address is valid.
// It panics with a detailed error message if the address is invalid.
func assertValidAddr(addr std.Address) {
if !addr.IsValid() {
panic(addDetailToError(errInvalidAddr, addr.String()))
}
}
115 changes: 115 additions & 0 deletions _deploy/r/gnoswap/common/address_and_username_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package common

import (
"std"
"testing"

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

func TestAddrToUser(t *testing.T) {
tests := []struct {
name string
addr std.Address
want pusers.AddressOrName
shouldPanic bool
panicMsg string
}{
{
name: "valid address",
addr: std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5"),
want: pusers.AddressOrName("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5"),
},
{
name: "empty address",
addr: std.Address(""),
shouldPanic: true,
panicMsg: `[GNOSWAP-COMMON-005] invalid address || `,
},
{
name: "invalid address",
addr: std.Address("invalid"),
shouldPanic: true,
panicMsg: `[GNOSWAP-COMMON-005] invalid address || invalid`,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.shouldPanic {
uassert.PanicsWithMessage(t, tt.panicMsg, func() {
AddrToUser(tt.addr)
})
} else {
got := AddrToUser(tt.addr)
if got != tt.want {
t.Errorf("AddrToUser() = %v, want %v", got, tt.want)
}
}
})
}
}

func TestUserToAddr(t *testing.T) {
tests := []struct {
name string
user pusers.AddressOrName
want std.Address
}{
{
name: "address string with user type",
user: pusers.AddressOrName("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5"),
want: std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5"),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := UserToAddr(tt.user)
if got != tt.want {
t.Errorf("UserToAddr() = %v, want %v", got, tt.want)
}
})
}
}

func TestAssertValidAddr(t *testing.T) {
tests := []struct {
name string
addr std.Address
shouldPanic bool
panicMsg string
}{
{
name: "valid address",
addr: std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5"),
},
{
name: "empty address",
addr: std.Address(""),
shouldPanic: true,
panicMsg: `[GNOSWAP-COMMON-005] invalid address || `,
},
{
name: "invalid address",
addr: std.Address("invalid"),
shouldPanic: true,
panicMsg: `[GNOSWAP-COMMON-005] invalid address || invalid`,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.shouldPanic {
uassert.PanicsWithMessage(t, tt.panicMsg, func() {
assertValidAddr(tt.addr)
})
} else {
uassert.NotPanics(t, func() {
assertValidAddr(tt.addr)
})
}
})
}
}
11 changes: 7 additions & 4 deletions _deploy/r/gnoswap/common/errors.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import (
)

var (
errNoPermission = errors.New("[GNOSWAP-COMMON-001] caller has no permission")
errHalted = errors.New("[GNOSWAP-COMMON-002] halted")
errOutOfRange = errors.New("[GNOSWAP-COMMON-003] value out of range")
errNotRegistered = errors.New("[GNOSWAP-COMMON-004] token is not registered")
errNoPermission = errors.New("[GNOSWAP-COMMON-001] caller has no permission")
errHalted = errors.New("[GNOSWAP-COMMON-002] halted")
errOutOfRange = errors.New("[GNOSWAP-COMMON-003] value out of range")
errNotRegistered = errors.New("[GNOSWAP-COMMON-004] token is not registered")
errInvalidAddr = errors.New("[GNOSWAP-COMMON-005] invalid address")
errOverflow = errors.New("[GNOSWAP-COMMON-006] overflow")
errInvalidTokenId = errors.New("[GNOSWAP-COMMON-007] invalid tokenId")
)

func addDetailToError(err error, detail string) string {
Expand Down
8 changes: 0 additions & 8 deletions _deploy/r/gnoswap/common/gno.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1 @@
module gno.land/r/gnoswap/v1/common

require (
gno.land/p/demo/ufmt v0.0.0-latest
gno.land/p/gnoswap/int256 v0.0.0-latest
gno.land/p/gnoswap/pool v0.0.0-latest
gno.land/p/gnoswap/uint256 v0.0.0-latest
gno.land/r/gnoswap/v1/consts v0.0.0-latest
)
19 changes: 18 additions & 1 deletion _deploy/r/gnoswap/common/grc20reg_helper.gno
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package common

import (
"std"

"gno.land/p/demo/grc/grc20"
"gno.land/p/demo/ufmt"
"gno.land/r/demo/grc20reg"
Expand Down Expand Up @@ -51,7 +53,22 @@ func MustRegistered(path string) {
if err := IsRegistered(path); err != nil {
panic(addDetailToError(
errNotRegistered,
ufmt.Sprintf("token(%s) is not registered", path),
ufmt.Sprintf("token(%s)", path),
))
}
}

// TotalSupply returns the total supply of the token
func TotalSupply(path string) uint64 {
return GetToken(path).TotalSupply()
}

// BalanceOf returns the balance of the token for the given address
func BalanceOf(path string, addr std.Address) uint64 {
return GetToken(path).BalanceOf(addr)
}

// Allowance returns the allowance of the token for the given owner and spender
func Allowance(path string, owner, spender std.Address) uint64 {
return GetToken(path).Allowance(owner, spender)
}
22 changes: 21 additions & 1 deletion _deploy/r/gnoswap/common/grc20reg_helper_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"gno.land/p/demo/uassert"
"gno.land/p/demo/ufmt"

_ "gno.land/r/demo/foo20"
"gno.land/r/demo/foo20"
)

var (
Expand Down Expand Up @@ -152,3 +152,23 @@ func TestMustRegistered(t *testing.T) {
MustRegistered("not_registered")
})
}

func TestTotalSupply(t *testing.T) {
// result from grc2reg and (direct import/call) should be the same
uassert.Equal(t, foo20.TotalSupply(), TotalSupply(tokenPath))
}

func TestBalanceOf(t *testing.T) {
defaultHolder := std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5")

// result from grc2reg and (direct import/call) should be the same
uassert.Equal(t, foo20.BalanceOf(AddrToUser(defaultHolder)), BalanceOf(tokenPath, defaultHolder))
}

func TestAllowance(t *testing.T) {
owner := std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5")
spender := std.Address("g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6")

// result from grc2reg and (direct import/call) should be the same
uassert.Equal(t, foo20.Allowance(AddrToUser(owner), AddrToUser(spender)), Allowance(tokenPath, owner, spender))
}
41 changes: 41 additions & 0 deletions _deploy/r/gnoswap/common/grc721_token_id.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package common

import (
"strconv"

"gno.land/p/demo/ufmt"

"gno.land/p/demo/grc/grc721"
)

// TokenIdFrom converts tokenId to grc721.TokenID type
// NOTE: input parameter tokenId can be string, int, uint64, or grc721.TokenID
// if tokenId is nil or not supported, it will panic
// if input type is not supported, it will panic
// input: tokenId interface{}
// output: grc721.TokenID
func TokenIdFrom(tokenId interface{}) grc721.TokenID {
if tokenId == nil {
panic(addDetailToError(
errInvalidTokenId,
"can not be nil",
))
}

switch tokenId.(type) {
case string:
return grc721.TokenID(tokenId.(string))
case int:
return grc721.TokenID(strconv.Itoa(tokenId.(int)))
case uint64:
return grc721.TokenID(strconv.Itoa(int(tokenId.(uint64))))
case grc721.TokenID:
return tokenId.(grc721.TokenID)
default:
estimatedType := ufmt.Sprintf("%T", tokenId)
panic(addDetailToError(
errInvalidTokenId,
ufmt.Sprintf("unsupported tokenId type: %s", estimatedType),
))
}
}
64 changes: 64 additions & 0 deletions _deploy/r/gnoswap/common/grc721_token_id_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package common

import (
"testing"

"gno.land/p/demo/grc/grc721"
)

func TestTokenIdFrom(t *testing.T) {
tests := []struct {
name string
input interface{}
want grc721.TokenID
wantPanic bool
}{
{
name: "string input",
input: "123",
want: grc721.TokenID("123"),
},
{
name: "int input",
input: 123,
want: grc721.TokenID("123"),
},
{
name: "uint64 input",
input: uint64(123),
want: grc721.TokenID("123"),
},
{
name: "grc721.TokenID input",
input: grc721.TokenID("123"),
want: grc721.TokenID("123"),
},
{
name: "nil input",
input: nil,
wantPanic: true,
},
{
name: "unsupported type (byte)",
input: []byte("123"),
wantPanic: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.wantPanic {
defer func() {
if r := recover(); r == nil {
t.Errorf("TokenIdFrom() should have panicked")
}
}()
}

got := TokenIdFrom(tt.input)
if got != tt.want {
t.Errorf("TokenIdFrom() = %v, want %v", got, tt.want)
}
})
}
}
Loading
Loading