forked from CosmWasm/wasmd
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
x/tokenfactory: add type files (CosmWasm#1361)
* add proto files * Update proto/osmosis/tokenfactory/v1beta1/authorityMetadata.proto Co-authored-by: Dev Ojha <ValarDragon@users.noreply.github.com> * update comments on proto * add other types files * Apply suggestions from code review Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com> * update errors to not start from 1 * add more comments Co-authored-by: Dev Ojha <ValarDragon@users.noreply.github.com> Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
- Loading branch information
1 parent
bf5d52e
commit 5f2453c
Showing
9 changed files
with
635 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package types | ||
|
||
import ( | ||
"github.com/cosmos/cosmos-sdk/codec" | ||
cdctypes "github.com/cosmos/cosmos-sdk/codec/types" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
|
||
// this line is used by starport scaffolding # 1 | ||
"github.com/cosmos/cosmos-sdk/types/msgservice" | ||
) | ||
|
||
func RegisterCodec(cdc *codec.LegacyAmino) { | ||
cdc.RegisterConcrete(&MsgCreateDenom{}, "osmosis/tokenfactory/create-denom", nil) | ||
cdc.RegisterConcrete(&MsgMint{}, "osmosis/tokenfactory/mint", nil) | ||
cdc.RegisterConcrete(&MsgBurn{}, "osmosis/tokenfactory/burn", nil) | ||
// cdc.RegisterConcrete(&MsgForceTransfer{}, "osmosis/tokenfactory/force-transfer", nil) | ||
cdc.RegisterConcrete(&MsgChangeAdmin{}, "osmosis/tokenfactory/change-admin", nil) | ||
} | ||
|
||
func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { | ||
registry.RegisterImplementations( | ||
(*sdk.Msg)(nil), | ||
&MsgCreateDenom{}, | ||
&MsgMint{}, | ||
&MsgBurn{}, | ||
// &MsgForceTransfer{}, | ||
&MsgChangeAdmin{}, | ||
) | ||
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) | ||
} | ||
|
||
var ( | ||
amino = codec.NewLegacyAmino() | ||
ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package types | ||
|
||
import ( | ||
"strings" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
) | ||
|
||
const ( | ||
ModuleDenomPrefix = "factory" | ||
) | ||
|
||
// GetTokenDenom constructs a denom string for tokens created by tokenfactory | ||
// based on an input creator address and a nonce | ||
// The denom constructed is factory/{creator}/{nonce} | ||
func GetTokenDenom(creator, nonce string) (string, error) { | ||
if strings.Contains(creator, "/") { | ||
return "", ErrInvalidCreator | ||
} | ||
denom := strings.Join([]string{ModuleDenomPrefix, creator, nonce}, "/") | ||
return denom, sdk.ValidateDenom(denom) | ||
} | ||
|
||
// DeconstructDenom takes a token denom string and verifies that it is a valid | ||
// denom of the tokenfactory module, and is of the form `factory/{creator}/{nonce}` | ||
// If valid, it returns the creator address and nonce | ||
func DeconstructDenom(denom string) (creator string, nonce string, err error) { | ||
err = sdk.ValidateDenom(denom) | ||
if err != nil { | ||
return "", "", err | ||
} | ||
|
||
strParts := strings.Split(denom, "/") | ||
if len(strParts) < 3 { | ||
return "", "", sdkerrors.Wrapf(ErrInvalidDenom, "not enough parts of denom %s", denom) | ||
} | ||
|
||
if strParts[0] != ModuleDenomPrefix { | ||
return "", "", sdkerrors.Wrapf(ErrInvalidDenom, "denom prefix is incorrect. Is: %s. Should be: %s", strParts[0], ModuleDenomPrefix) | ||
} | ||
|
||
creator = strParts[1] | ||
_, err = sdk.AccAddressFromBech32(creator) | ||
if err != nil { | ||
return "", "", sdkerrors.Wrapf(ErrInvalidDenom, "Invalid creator address (%s)", err) | ||
} | ||
|
||
// Handle the case where a denom has a slash in its nonce. For example, | ||
// when we did the split, we'd turn factory/sunnyaddr/atomderivative/sikka into ["factory", "sunnyaddr", "atomderivative", "sikka"] | ||
// So we have to join [2:] with a "/" as the delimiter to get back the correct nonce which should be "atomderivative/sikka" | ||
nonce = strings.Join(strParts[2:], "/") | ||
|
||
return creator, nonce, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package types_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
appparams "github.com/osmosis-labs/osmosis/v7/app/params" | ||
"github.com/osmosis-labs/osmosis/v7/x/tokenfactory/types" | ||
) | ||
|
||
func TestDecomposeDenoms(t *testing.T) { | ||
appparams.SetAddressPrefixes() | ||
for _, tc := range []struct { | ||
desc string | ||
denom string | ||
valid bool | ||
}{ | ||
{ | ||
desc: "empty is invalid", | ||
denom: "", | ||
valid: false, | ||
}, | ||
{ | ||
desc: "normal", | ||
denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/bitcoin", | ||
valid: true, | ||
}, | ||
{ | ||
desc: "multiple slashes in nonce", | ||
denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/bitcoin/1", | ||
valid: true, | ||
}, | ||
{ | ||
desc: "no nonce", | ||
denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/", | ||
valid: true, | ||
}, | ||
{ | ||
desc: "incorrect prefix", | ||
denom: "ibc/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/bitcoin", | ||
valid: false, | ||
}, | ||
{ | ||
desc: "nonce of only slashes", | ||
denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/////", | ||
valid: true, | ||
}, | ||
{ | ||
desc: "too long name", | ||
denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/adsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsf", | ||
valid: false, | ||
}, | ||
} { | ||
t.Run(tc.desc, func(t *testing.T) { | ||
_, _, err := types.DeconstructDenom(tc.denom) | ||
if tc.valid { | ||
require.NoError(t, err) | ||
} else { | ||
require.Error(t, err) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package types | ||
|
||
// DONTCOVER | ||
|
||
import ( | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
) | ||
|
||
// x/tokenfactory module sentinel errors | ||
var ( | ||
ErrDenomExists = sdkerrors.Register(ModuleName, 2, "denom already exists") | ||
ErrUnauthorized = sdkerrors.Register(ModuleName, 3, "unauthorized account") | ||
ErrInvalidDenom = sdkerrors.Register(ModuleName, 4, "invalid denom") | ||
ErrInvalidCreator = sdkerrors.Register(ModuleName, 5, "invalid creator") | ||
ErrInvalidAuthorityMetadata = sdkerrors.Register(ModuleName, 6, "invalid authority metadata") | ||
ErrInvalidGenesis = sdkerrors.Register(ModuleName, 7, "invalid genesis") | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package types | ||
|
||
// event types | ||
const ( | ||
AttributeAmount = "amount" | ||
AttributeCreator = "creator" | ||
AttributeNonce = "nonce" | ||
AttributeNewTokenDenom = "new_token_denom" | ||
AttributeMintToAddress = "mint_to_address" | ||
AttributeBurnFromAddress = "burn_from_address" | ||
AttributeTransferFromAddress = "transfer_from_address" | ||
AttributeTransferToAddress = "transfer_to_address" | ||
AttributeDenom = "denom" | ||
AttributeNewAdmin = "new_admin" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package types | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
) | ||
|
||
// this line is used by starport scaffolding # genesis/types/import | ||
|
||
// DefaultIndex is the default capability global index | ||
const DefaultIndex uint64 = 1 | ||
|
||
// DefaultGenesis returns the default Capability genesis state | ||
func DefaultGenesis() *GenesisState { | ||
return &GenesisState{ | ||
FactoryDenoms: []GenesisDenom{}, | ||
} | ||
} | ||
|
||
// Validate performs basic genesis state validation returning an error upon any | ||
// failure. | ||
func (gs GenesisState) Validate() error { | ||
seenDenoms := map[string]bool{} | ||
|
||
for _, denom := range gs.GetFactoryDenoms() { | ||
if seenDenoms[denom.GetDenom()] { | ||
return sdkerrors.Wrapf(ErrInvalidGenesis, "duplicate denom: %s", denom.GetDenom()) | ||
} | ||
seenDenoms[denom.GetDenom()] = true | ||
|
||
_, _, err := DeconstructDenom(denom.GetDenom()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if denom.AuthorityMetadata.Admin != "" { | ||
_, err = sdk.AccAddressFromBech32(denom.AuthorityMetadata.Admin) | ||
if err != nil { | ||
return sdkerrors.Wrapf(ErrInvalidAuthorityMetadata, "Invalid admin address (%s)", err) | ||
} | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package types_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/osmosis-labs/osmosis/v7/x/tokenfactory/types" | ||
) | ||
|
||
func TestGenesisState_Validate(t *testing.T) { | ||
for _, tc := range []struct { | ||
desc string | ||
genState *types.GenesisState | ||
valid bool | ||
}{ | ||
{ | ||
desc: "default is valid", | ||
genState: types.DefaultGenesis(), | ||
valid: true, | ||
}, | ||
{ | ||
desc: "valid genesis state", | ||
genState: &types.GenesisState{ | ||
FactoryDenoms: []types.GenesisDenom{ | ||
{ | ||
Denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/bitcoin", | ||
AuthorityMetadata: types.DenomAuthorityMetadata{ | ||
Admin: "osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44", | ||
}, | ||
}, | ||
}, | ||
}, | ||
valid: true, | ||
}, | ||
{ | ||
desc: "different admin from creator", | ||
genState: &types.GenesisState{ | ||
FactoryDenoms: []types.GenesisDenom{ | ||
{ | ||
Denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/bitcoin", | ||
AuthorityMetadata: types.DenomAuthorityMetadata{ | ||
Admin: "osmo1ft6e5esdtdegnvcr3djd3ftk4kwpcr6jrx5fj9", | ||
}, | ||
}, | ||
}, | ||
}, | ||
valid: true, | ||
}, | ||
{ | ||
desc: "empty admin", | ||
genState: &types.GenesisState{ | ||
FactoryDenoms: []types.GenesisDenom{ | ||
{ | ||
Denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/bitcoin", | ||
AuthorityMetadata: types.DenomAuthorityMetadata{ | ||
Admin: "", | ||
}, | ||
}, | ||
}, | ||
}, | ||
valid: true, | ||
}, | ||
{ | ||
desc: "no admin", | ||
genState: &types.GenesisState{ | ||
FactoryDenoms: []types.GenesisDenom{ | ||
{ | ||
Denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/bitcoin", | ||
}, | ||
}, | ||
}, | ||
valid: true, | ||
}, | ||
{ | ||
desc: "invalid admin", | ||
genState: &types.GenesisState{ | ||
FactoryDenoms: []types.GenesisDenom{ | ||
{ | ||
Denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/bitcoin", | ||
AuthorityMetadata: types.DenomAuthorityMetadata{ | ||
Admin: "moose", | ||
}, | ||
}, | ||
}, | ||
}, | ||
valid: false, | ||
}, | ||
{ | ||
desc: "multiple denoms", | ||
genState: &types.GenesisState{ | ||
FactoryDenoms: []types.GenesisDenom{ | ||
{ | ||
Denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/bitcoin", | ||
AuthorityMetadata: types.DenomAuthorityMetadata{ | ||
Admin: "", | ||
}, | ||
}, | ||
{ | ||
Denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/litecoin", | ||
AuthorityMetadata: types.DenomAuthorityMetadata{ | ||
Admin: "", | ||
}, | ||
}, | ||
}, | ||
}, | ||
valid: true, | ||
}, | ||
{ | ||
desc: "duplicate denoms", | ||
genState: &types.GenesisState{ | ||
FactoryDenoms: []types.GenesisDenom{ | ||
{ | ||
Denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/bitcoin", | ||
AuthorityMetadata: types.DenomAuthorityMetadata{ | ||
Admin: "", | ||
}, | ||
}, | ||
{ | ||
Denom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/bitcoin", | ||
AuthorityMetadata: types.DenomAuthorityMetadata{ | ||
Admin: "", | ||
}, | ||
}, | ||
}, | ||
}, | ||
valid: false, | ||
}, | ||
} { | ||
t.Run(tc.desc, func(t *testing.T) { | ||
err := tc.genState.Validate() | ||
if tc.valid { | ||
require.NoError(t, err) | ||
} else { | ||
require.Error(t, err) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.