diff --git a/examples/gno.land/r/demo/foo20/foo20_test.gno b/examples/gno.land/r/demo/foo20/foo20_test.gno index 9db0d5f7a6e..38bdcb333c1 100644 --- a/examples/gno.land/r/demo/foo20/foo20_test.gno +++ b/examples/gno.land/r/demo/foo20/foo20_test.gno @@ -4,13 +4,14 @@ import ( "std" "testing" - "gno.land/p/demo/users" + pusers "gno.land/p/demo/users" + "gno.land/r/demo/users" ) func TestReadOnlyPublicMethods(t *testing.T) { - admin := users.AddressOrName("g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj") - manfred := users.AddressOrName("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") - unknown := std.Address("g1u0000000000000000000000000000000000000") + admin := pusers.AddressOrName("g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj") + manfred := pusers.AddressOrName("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") + unknown := pusers.AddressOrName("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // valid but never used. type test struct { name string @@ -25,7 +26,7 @@ func TestReadOnlyPublicMethods(t *testing.T) { {"BalanceOf(admin)", 10000000000, func() uint64 { return BalanceOf(admin) }}, {"BalanceOf(manfred)", 100000000, func() uint64 { return BalanceOf(manfred) }}, {"Allowance(admin, manfred)", 0, func() uint64 { return Allowance(admin, manfred) }}, - {"BalanceOf(unknown)", 0, func() uint64 { return BalanceOf(users.AddressOrName(unknown)) }}, + {"BalanceOf(unknown)", 0, func() uint64 { return BalanceOf(unknown) }}, } for _, tc := range tests { if tc.fn() != tc.balance { @@ -35,7 +36,7 @@ func TestReadOnlyPublicMethods(t *testing.T) { } // unknown uses the faucet. - std.TestSetOrigCaller(unknown) + std.TestSetOrigCaller(users.Resolve(unknown)) Faucet() // check balances #2. @@ -45,7 +46,7 @@ func TestReadOnlyPublicMethods(t *testing.T) { {"BalanceOf(admin)", 10000000000, func() uint64 { return BalanceOf(admin) }}, {"BalanceOf(manfred)", 100000000, func() uint64 { return BalanceOf(manfred) }}, {"Allowance(admin, manfred)", 0, func() uint64 { return Allowance(admin, manfred) }}, - {"BalanceOf(unknown)", 10000000, func() uint64 { return BalanceOf(users.AddressOrName(unknown)) }}, + {"BalanceOf(unknown)", 10000000, func() uint64 { return BalanceOf(unknown) }}, } for _, tc := range tests { if tc.fn() != tc.balance { @@ -68,8 +69,8 @@ func TestErrConditions(t *testing.T) { std.TestSetOrigCaller(admin) { tests := []test{ - {"Transfer(admin, 1)", "cannot send transfer to self", func() { Transfer(users.AddressOrName(admin), 1) }}, - {"Approve(empty, 1))", "invalid address", func() { Approve(users.AddressOrName(empty), 1) }}, + {"Transfer(admin, 1)", "cannot send transfer to self", func() { Transfer(pusers.AddressOrName(admin), 1) }}, + {"Approve(empty, 1))", "invalid address", func() { Approve(pusers.AddressOrName(empty), 1) }}, } for _, tc := range tests { shouldPanicWithMsg(t, tc.fn, tc.msg) diff --git a/gno.land/cmd/gnoland/testdata/grc20-invalid-address.txtar b/gno.land/cmd/gnoland/testdata/grc20-invalid-address.txtar new file mode 100644 index 00000000000..da903315333 --- /dev/null +++ b/gno.land/cmd/gnoland/testdata/grc20-invalid-address.txtar @@ -0,0 +1,12 @@ +# Test for https://github.com/gnolang/gno/pull/1799 +loadpkg gno.land/r/demo/foo20 + +gnoland start + +# execute Faucet +gnokey maketx call -pkgpath gno.land/r/demo/foo20 -func Faucet -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +stdout 'OK!' + +# execute Transfer for invalid address +! gnokey maketx call -pkgpath gno.land/r/demo/foo20 -func Transfer -args g1ubwj0apf60hd90txhnh855fkac34rxlsvua0aa -args 1 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +stderr '"gnokey" error: --= Error =--\nData: invalid address' \ No newline at end of file diff --git a/gnovm/stdlibs/std/crypto.gno b/gnovm/stdlibs/std/crypto.gno index 8d005dccf5c..402a6af3e22 100644 --- a/gnovm/stdlibs/std/crypto.gno +++ b/gnovm/stdlibs/std/crypto.gno @@ -6,9 +6,10 @@ func (a Address) String() string { return string(a) } -// IsValid checks if the address is of specific length. Doesn't check prefix or checksum for the address +// IsValid checks if the address is valid bech32 encoded string func (a Address) IsValid() bool { - return len(a) == RawAddressSize*2 // hex length + _, _, ok := DecodeBech32(a) + return ok } const RawAddressSize = 20 diff --git a/gnovm/stdlibs/std/crypto_test.gno b/gnovm/stdlibs/std/crypto_test.gno index 293f3e06945..75283c03523 100644 --- a/gnovm/stdlibs/std/crypto_test.gno +++ b/gnovm/stdlibs/std/crypto_test.gno @@ -15,6 +15,17 @@ func TestValid(t *testing.T) { {inputAddress: "g127jydsh6cms3lrtdenydxsckh23a8d6emqcvfa", expected: true}, {inputAddress: "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq", expected: true}, {inputAddress: "g14da4n9hcynyzz83q607uu8keuh9hwlv42ra6fa", expected: true}, + + // Bech32 doesn't allow '1', 'b', 'i', 'o' for data part + // + // https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 + {inputAddress: "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5", expected: true}, + {inputAddress: "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf1", expected: false}, + {inputAddress: "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqfb", expected: false}, + {inputAddress: "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqfi", expected: false}, + {inputAddress: "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqfo", expected: false}, + + {inputAddress: "g1u0000000000000000000000000000000000000", expected: false}, {inputAddress: "", expected: false}, {inputAddress: "000000000000", expected: false}, {inputAddress: "0000000000000000000000000000000000000000000000000000000000000000000000", expected: false}, diff --git a/gnovm/stdlibs/stdshim/crypto.gno b/gnovm/stdlibs/stdshim/crypto.gno index 8d005dccf5c..402a6af3e22 100644 --- a/gnovm/stdlibs/stdshim/crypto.gno +++ b/gnovm/stdlibs/stdshim/crypto.gno @@ -6,9 +6,10 @@ func (a Address) String() string { return string(a) } -// IsValid checks if the address is of specific length. Doesn't check prefix or checksum for the address +// IsValid checks if the address is valid bech32 encoded string func (a Address) IsValid() bool { - return len(a) == RawAddressSize*2 // hex length + _, _, ok := DecodeBech32(a) + return ok } const RawAddressSize = 20